簡體   English   中英

在 C# 中解析此字符串的最佳方法是什么?

[英]What is the best way to parse this string in C#?

我有一個從另一個系統讀取的字符串。 它基本上是一個長字符串,表示一個鍵值對列表,它們之間用空格分隔。 它看起來像這樣:

 key:value[space]key:value[space]key:value[space]

所以我寫了這段代碼來解析它:

string myString = ReadinString();
string[] tokens = myString.split(' ');
foreach (string token in tokens) {
     string key = token.split(':')[0];
     string value = token.split(':')[1];
     .  . . . 
}

現在的問題是某些值中有空格,因此我在頂部的“簡單”拆分不再有效。 我想看看我如何仍然可以解析出鍵值對列表(給定空格作為分隔符),因為我知道值字段中也可能有空格,因為 split 似乎無法做到工作了。

注意:我現在確認鍵中不會有空格,所以我只需要擔心值。 為混亂道歉。

使用這個正則表達式:

\w+:[\w\s]+(?![\w+:])

我在上面測試過

test:testvalue test2:test value test3:testvalue3

它返回三個匹配項:

test:testvalue
test2:test value
test3:testvalue3

您可以將\w更改為輸入中可能出現的任何字符集。

用於測試的代碼:

var regex = new Regex(@"\w+:[\w\s]+(?![\w+:])");
var test = "test:testvalue test2:test value test3:testvalue3";

foreach (Match match in regex.Matches(test))
{
    var key = match.Value.Split(':')[0];
    var value = match.Value.Split(':')[1];

    Console.WriteLine("{0}:{1}", key, value);
}
Console.ReadLine();

正如 Wonko the Sane 指出的那樣,這個正則表達式將在帶有:的值上失敗。 如果您預測這種情況,請使用\w+:[\w: ]+?(?:[\w+:])作為正則表達式。 但是,當value中的冒號前面有空格時,這仍然會失敗......我會考慮解決這個問題。

如果不將拆分從空格更改為“|”等其他內容,這將無法工作。

考慮一下:

阿爾弗雷德·貝斯特:阿爾弗雷德·貝斯特 阿爾弗雷德·阿爾弗雷德·貝斯特

  • 這是 Key "Alfred Bester" & value Alfred" 還是 Key "Alfred" & value "Bester Alfred"?
string input = "foo:Foobarius Maximus Tiberius Kirk bar:Barforama zap:Zip Brannigan";

foreach (Match match in Regex.Matches(input, @"(\w+):([^:]+)(?![\w+:])"))
{
   Console.WriteLine("{0} = {1}", 
       match.Groups[1].Value, 
       match.Groups[2].Value
      );
}

給你:

foo = Foobarius Maximus Tiberius Kirk
bar = Barforama
zap = Zip Brannigan

您可以嘗試 Url 對空格之間的內容進行編碼(鍵和值不是:符號),但這需要您控制輸入法。

或者您可以簡單地使用另一種格式(如 XML 或 JSON),但您需要再次控制輸入格式。

如果您無法控制輸入格式,您始終可以使用正則表達式並搜索單詞 plus: 后面的單個空格。

更新(感謝 Jon Grant)看來您可以在鍵和值中有空格。 如果是這種情況,您將需要認真重新考慮您的策略,因為即使正則表達式也無濟於事。

string input = "key1:value key2:value key3:value";
Dictionary<string, string> dic = input.Split(' ').Select(x => x.Split(':')).ToDictionary(x => x[0], x => x[1]);

第一個將產生一個數組:

"key:value", "key:value"

然后是arrays的數組:

{ "key", "value" }, { "key", "value" }

然后是字典:

"key" => "value", "key" => "value"

請注意, Dictionary<K,V>不允許重復鍵,在這種情況下會引發異常。 如果可能出現這種情況,請使用ToLookup()

使用正則表達式可以解決您的問題:

private void DoSplit(string str)
{
    str += str.Trim() + " ";
    string patterns = @"\w+:([\w+\s*])+[^!\w+:]";
    var r = new System.Text.RegularExpressions.Regex(patterns);
    var ms = r.Matches(str);
    foreach (System.Text.RegularExpressions.Match item in ms)
    {
        string[] s = item.Value.Split(new char[] { ':' });
        //Do something
    }
}

我想你可以采用你的方法並稍微擴展它來處理這些東西......

偽代碼種類:

List<string> parsedTokens = new List<String>();
string[] tokens = myString.split(' ');
for(int i = 0; i < tokens.Length; i++)
{
    // We need to deal with the special case of the last item, 
    // or if the following item does not contain a colon.
    if(i == tokens.Length - 1 || tokens[i+1].IndexOf(':' > -1)
    {
        parsedTokens.Add(tokens[i]);
    }
    else
    {
        // This bit needs to be refined to deal with values with multiple spaces...
        parsedTokens.Add(tokens[i] + " " + tokens[i+1]);
    }
}

另一種方法是在冒號上拆分......這樣,您的第一個數組項將是第一個鍵的名稱,第二個項目將是第一個鍵的值,然后是第二個鍵的名稱(可以使用 LastIndexOf分開),等等。 如果值可以包含冒號,或者鍵可以包含空格,這顯然會變得非常混亂,但在這種情況下,你會很不走運......

此代碼將執行此操作(鑒於以下規則)。 它解析鍵和值並以Dictonary<string, string>數據結構返回它們。 我在最后添加了一些代碼,假設給定您的示例,整個字符串/流的最后一個值將附加一個 [空格]:

private Dictionary<string, string> ParseKeyValues(string input)
        {
            Dictionary<string, string> items = new Dictionary<string, string>();

            string[] parts = input.Split(':');

            string key = parts[0];
            string value;

            int currentIndex = 1;

            while (currentIndex < parts.Length-1)
            {
                int indexOfLastSpace=parts[currentIndex].LastIndexOf(' ');
                value = parts[currentIndex].Substring(0, indexOfLastSpace);
                items.Add(key, value);
                key = parts[currentIndex].Substring(indexOfLastSpace + 1);
                currentIndex++;
            }
            value = parts[parts.Length - 1].Substring(0,parts[parts.Length - 1].Length-1);


            items.Add(key, parts[parts.Length-1]);

            return items;

        }

注意:此算法假定以下規則:

  1. 值中沒有空格
  2. 鍵中沒有冒號
  3. 值中沒有冒號

沒有任何正則表達式或字符串連接,並且作為可枚舉(它假設鍵沒有空格,但值可以):

    public static IEnumerable<KeyValuePair<string, string>> Split(string text)
    {
        if (text == null)
            yield break;

        int keyStart = 0;
        int keyEnd = -1;
        int lastSpace = -1;
        for(int i = 0; i < text.Length; i++)
        {
            if (text[i] == ' ')
            {
                lastSpace = i;
                continue;
            }

            if (text[i] == ':')
            {
                if (lastSpace >= 0)
                {
                    yield return new KeyValuePair<string, string>(text.Substring(keyStart, keyEnd - keyStart), text.Substring(keyEnd + 1, lastSpace - keyEnd - 1));
                    keyStart = lastSpace + 1;
                }
                keyEnd = i;
                continue;
            }
        }
        if (keyEnd >= 0)
            yield return new KeyValuePair<string, string>(text.Substring(keyStart, keyEnd - keyStart), text.Substring(keyEnd + 1));
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM