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

时间:2011-05-31 10:58:59

标签: c# .net string parsing

我有一个字符串,我正在从另一个系统中读取。它基本上是一个长字符串,表示由两者之间的空格分隔的键值对列表。它看起来像这样:

 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];
     .  . . . 
}

现在的问题是某些值中包含空格,因此我在顶部的“简单”拆分不再有效。我想知道如何解析键值对的列表(给定空格作为分隔符)现在我知道值字段中也可能有空格,因为拆分看起来不像它能够再努力了。

注意:我现在确认KEYs中没有空格,所以我只需要担心这些值。为混乱道歉。

9 个答案:

答案 0 :(得分:22)

使用此正则表达式:

\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();

正如Sane所指出的Wonko,这个正则表达式将在:的值上失败。如果您预测到这种情况,请使用\w+:[\w: ]+?(?![\w+:])作为正则表达式。当value中的冒号前面有空格时,这仍然会失败......我会考虑解决这个问题。

答案 1 :(得分:5)

如果不将分割从空格更改为其他内容(例如“|”),则无法使用。

考虑一下:

Alfred Bester: Alfred Bester Alfred :Alfred Bester

  • 这是Key“Alfred Bester”&价值Alfred“或Key”Alfred“& value”Bester Alfred“?

答案 2 :(得分:4)

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

答案 3 :(得分:2)

您可以尝试在空格(键和值而不是:符号)之间对内容进行Url编码,但这需要您可以控制输入法。

或者您可以简单地使用其他格式(如XML或JSON),但您需要再次控制输入格式。

如果您无法控制输入格式,则可以始终使用正则表达式,并搜索单词空格,其中单词加上:。

更新(感谢Jon Grant) 您似乎可以在键和值中包含空格。如果是这种情况,您将需要认真重新考虑您的策略,因为即使Regex也无济于事。

答案 4 :(得分:1)

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"

然后是一个数组数组:

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

然后是字典:

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

注意,Dictionary<K,V>不允许重复密钥,在这种情况下会引发异常。如果可能出现这种情况,请使用ToLookup()

答案 5 :(得分:1)

使用正则表达式可以解决您的问题:

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
    }
}

答案 6 :(得分:0)

我想你可以采取你的方法并稍微扩展它以处理这些东西......

有点伪代码:

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将其拆分出来,等等。如果值可以包含冒号,或者键可以包含空格,这显然会变得非常混乱,但在这种情况下,你几乎没有运气......

答案 7 :(得分:0)

此代码将执行此操作(根据以下规则)。它解析键和值,并以Dictonary<string, string>数据结构返回它们。我在最后添加了一些代码,假设您的示例是整个字符串/流的最后一个值将附加[space]:

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. 值中没有冒号

答案 8 :(得分:0)

没有任何正则表达式和字符串连接,并且作为可枚举(假设键没有空格,但值可以):

    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));
    }