1

次の文字列があります

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

まず、行に分割する必要があるため、各行を ' =' 文字で分割して、その行からキーと値を取得する必要があります。結果として、私が欲しいのはList<KeyValuePair<string, string>>(なぜではないのDictionaryですか?=>リスト内に重複するキーがあるかもしれません)ので、.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

4 に答える 4

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" ]
于 2013-07-16T12:49:58.380 に答える
2

Lookup<TKey, TValue>辞書の代わりに a を使用できます。

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

于 2013-07-16T12:53:38.980 に答える
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]);
于 2013-07-16T12:50:14.317 に答える
0

分割するのではなく、キーと値を一致させることをお勧めします。キーに複数の値を持つ辞書が必要な場合は、ToLookup(an ILookup)を使用できます。

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

注: 使用されている正規表現は、入力内容がわからないため、使用に適していない可能性があります。

于 2013-07-16T12:53:45.963 に答える