Вопрос по c#, linq, regex – C # Linq .ToDictionary () ключ уже существует

5

Final Edit: I was able to locate the duplicate field in the ini file. Thanks for your help everyone!

Я использую регулярное выражение для анализа ini-файла и LINQ для сохранения его в словаре:

Sample Data:
[WindowSettings]
Window X Pos='0'
Window Y Pos='0'
Window Maximized='false'
Window Name='Jabberwocky'

[Logging]
Directory='C:\Rosetta Stone\Logs'

EDIT: Here is the file actually causing the problem: http://pastebin.com/mQSrkrcP

EDIT2: I've narrowed it down to being caused by the last section in the file: [list_first_nonprintable]

По какой-то причине один из файлов, с которыми я разбираю это, выдает это исключение:

System.ArgumentException: An item with the same key has already been added.

Могу ли я узнать, какой ключ вызывает проблему (чтобы я мог исправить файл), или просто пропустить ключ, вызывающий это, и продолжить анализ?

Вот код:

try
{
    // Read content of ini file.
    string data = System.IO.File.ReadAllText(project);

    // Create regular expression to parse ini file.
    string pattern = @"^((?:\[)(?<Section>[^\]]*)(?:\])(?:[\r\n]{0,}|\Z))((?!\[)(?<Key>[^=]*?)(?:=)(?<Value>[^\r\n]*)(?:[\r\n]{0,4}))*";
    //pattern = @"
    //^                           # Beginning of the line
    //((?:\[)                     # Section Start
    //     (?<Section>[^\]]*)     # Actual Section text into Section Group
    // (?:\])                     # Section End then EOL/EOB
    // (?:[\r\n]{0,}|\Z))         # Match but don't capture the CRLF or EOB
    // (                          # Begin capture groups (Key Value Pairs)
    //  (?!\[)                    # Stop capture groups if a [ is found; new section
    //  (?<Key>[^=]*?)            # Any text before the =, matched few as possible
    //  (?:=)                     # Get the = now
    //  (?<Value>[^\r\n]*)        # Get everything that is not an Line Changes
    //  (?:[\r\n]{0,4})           # MBDC \r\n
    //  )*                        # End Capture groups";

    // Parse each file into a Dictionary.
    Dictionary<string, Dictionary<string, string>> iniFile
                    = (from Match m in Regex.Matches(data, pattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline)
                       select new
                       {
                           Section = m.Groups["Section"].Value,

                           kvps = (from cpKey in m.Groups["Key"].Captures.Cast<Capture>().Select((a, i) => new { a.Value, i })
                                   join cpValue in m.Groups["Value"].Captures.Cast<Capture>().Select((b, i) => new { b.Value, i }) on cpKey.i equals cpValue.i
                                   select new KeyValuePair<string, string>(cpKey.Value, cpValue.Value)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)

                       }).ToDictionary(itm => itm.Section, itm => itm.kvps);

    return iniFile;
}
catch (ArgumentException ex)
{
    System.Diagnostics.Debug.Write(ex.ToString());
    return new Dictionary<string, Dictionary<string, string>>();
}

Заранее спасибо.

@TonyTrozzo вToLookup вместоToDictionary, пройдите поиск и проверьте, какие клавиши появляются более одного раза. Я почти уверен, что ключ, который появляется несколько раз, будет пустой строкой. dasblinkenlight
Вы пытались отладить результаты, которые вы получаете из своего регулярного выражения? Он производит один и тот же ключ дважды. James Michael Hare
@dasblinkenlight: Бьюсь об заклад, вы правы, в этом случае он мог бы добавить предложение Where (), чтобы убрать это ... James Michael Hare
Когда я запускаю ваш код на примере данных, кажется, все работает нормально. Вы проверили свой INI-файл, чтобы убедиться, что в нем нет объявленного раздела более одного раза? Rich McCollister
Тони, я провел запрос к твоим данным. У вас есть дубликат в разделе list_first_nonprintable. field26 использовался дважды. На pastbin, строка 491 и строка 496. Я предполагаю, что второй является опечаткой и должен быть field27. Rich McCollister

Ваш Ответ

3   ответа
0

Tuple передать несколько ключей. Проверьте пример кода ниже:

.ToDictionary(k => new Tuple<string,string>(k.key1,k.key2), v => v.value)
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceedededit your answerError: User Rate Limit Exceeded
4

Вы можете написать свой собственный метод ToDictionary, который достаточно легко разбивается на дубликаты ключей.

public static Dictionary<K,V> ToDictionary<TSource, K, V>(
    this IEnumerable<TSource> source, 
    Func<TSource, K> keySelector, 
    Funct<TSource, V> valueSelector)
{
  //TODO validate inputs for null arguments.

  Dictionary<K,V> output = new Dictionary<K,V>();
  foreach(TSource item in source)
  {
    //overwrites previous values
    output[keySelector(item)] = valueSelector(item); 

    //ignores future duplicates, comment above and 
    //uncomment below to change behavior
    //K key = keySelector(item);
    //if(!output.ContainsKey(key))
    //{
      //output.Add(key, valueSelector(item));
    //}
  }

  return output;
}

Я предполагаю, что вы могли бы выяснить, как реализовать дополнительные перегрузки (без значения селектора).

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededAdd.
10

Это просто означает, что когда вы преобразуете в словарь -

.ToDictionary(itm => itm.Section, itm => itm.kvps);

- есть несколько ключей (ит.секция). Ты можешь использоватьToLookup вместо этого, что-то вроде словаря, но допускает несколько ключей.

Edit

Есть несколько способов позвонитьToLookup, Проще всего указать ключевой селектор:

var lookup = 
   // ...
.ToLookup(itm => itm.Section);

Это должно обеспечить поиск, где ключ имеет типGroup, Получение значения поиска должно затем возвратить IEnumerable, где T - анонимный тип:

Group g = null;
// TODO get group
var lookupvalues = lookup[g];

Если компилятору .NET это не нравится (иногда возникает проблема с определением того, какими должны быть различные типы), вы также можете указать селектор элемента, например:

ILookup<string, KeyValuePair<string,string>> lookup = 
    // ...
.ToLookup(
    itm => itm.Section.Value,    // key selector
    itm => itm.kvps              // element selector
);
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Tony Trozzo
Error: User Rate Limit Exceeded Tony Trozzo
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы