LINQ方法用键/值解析行

时间:2013-07-16 12:47:12

标签: c# string linq parsing

我有以下字符串

 MyKey1=MyVal1
 MyKey2=MyVal2
 MyKey3=MyVal3
 MyKey3=MyVal3

首先,需要分割成行,然后我需要将每一行拆分为“=”字符来获取该行的键和值。因此,我想要的是List<KeyValuePair<string, string>>(为什么不是Dictionary?=&gt;列表中可能有重复的键),所以我无法使用.ToDictionary()扩展

我非常坚持以下内容:

List<KeyValuePair<string, string>> fields =
    (from lines in Regex.Split(input, @"\r?\n|\r", RegexOptions.None)
    where !String.IsNullOrWhiteSpace(lines)
    .Select(x => x.Split(new [] { '='}, 2, StringSplitOptions.RemoveEmptyEntries))
    .ToList()

    --> select new KeyValuePair? Or with 'let' for splitting by '='?
        what about exception handling (e.g. ignoring empty values)

4 个答案:

答案 0 :(得分:2)

如果您担心重复的密钥,可以使用ILookup代替:

var fields =
    (from line in Regex.Split(input, @"\r?\n|\r", RegexOptions.None)
     select line.Split(new [] { '=' }, 2))
    .ToLookup(x => x[0], x => x[1]);

var items = fields["MyKey3"]; // [ "MyVal3", "MyVal3" ]

答案 1 :(得分:2)

您可以使用Lookup<TKey, TValue>代替词典:

var keyValLookup = text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
    .Select(l =>
    {
        var keyVal = l.Split('=');
        return new { Key = keyVal[0].Trim(), Value = keyVal.ElementAtOrDefault(1) };
    })
    .Where(x => x.Key.Length > 0)  // not required, just to show how to handle invalid data
    .ToLookup(x => x.Key, x => x.Value);

IEnumerable<string> values = keyValLookup["MyKey3"];
Console.Write(string.Join(", ",values)); // MyVal3, MyVal3

即使密钥不存在,查找也始终返回值。然后它是一个空序列。密钥不能是唯一的,因此在使用ToLookup之前,您无需分组或删除重复项。

答案 2 :(得分:1)

你非常接近(我将你的例子改为所有方法语法以保持一致性):

List<KeyValuePair<string, string>> fields =
    Regex.Split(input, @"\r?\n|\r", RegexOptions.None)
    .Where(s => !String.IsNullOrWhiteSpace(s))
    .Select(x => x.Split(new [] {'='}, 2, StringSplitOptions.RemoveEmptyEntries)
    .Where(p => p.Length == 2)  // to avoid IndexOutOfRangeException
    .Select(p => new KeyValuePair(p[0], p[1]));

虽然我同意Jon的评论,如果你有重复的密钥,分组会更清晰:

IEnumerable<IGrouping<string, string>> fields =
    Regex.Split(input, @"\r?\n|\r", RegexOptions.None)
    .Where(s => !String.IsNullOrWhiteSpace(s))
    .Select(x => x.Split(new [] {'='}, 2, StringSplitOptions.RemoveEmptyEntries))
    .GroupBy(p => p[0]);

答案 3 :(得分:0)

我建议您尝试匹配键/值而不是分割。如果您想要一个包含多个键值的词典,可以使用ToLookupILookup}:

var result = Regex.Matches(input, @"(?<key>[^=\r\n]+)=(?<value>[^=\r\n]+)")
                  .OfType<Match>()
                  .ToLookup(m => m.Groups["key"].Value, 
                            m => m.Groups["value"].Value);

如果您稍后需要添加到该列表或想要继续使用列表:

var result = Regex.Matches(input, @"(?<key>[^=\r\n]+)=(?<value>[^=\r\n]+)")
                  .OfType<Match>()
                  .Select(m => new KeyValuePair<string, string>(m.Groups["key"].Value, m.Groups["value"].Value))
                    .ToList();

注意:使用的正则表达式可能不适合您的用途,因为我们不知道您可能有的输入。