Как разбить строку на массив - PullRequest
2 голосов
/ 26 июля 2010

У меня есть строка с именами и определениями атрибутов. Я пытаюсь разбить строку по имени атрибута в словарь строковой строки. Где ключ - это имя атрибута, а определение - это значение. Я не буду знать имена атрибутов раньше времени, поэтому я пытался как-то разделить символ «:», но у меня возникли проблемы с этим, поскольку имя атрибута не включено в разделение.

Например, мне нужно разбить эту строку на «Organization:», «OranizationType:» и «Nationality:» в словарь. Любые идеи о том, как сделать это с C # .Net?

Организация: Название правительственной, военной или другой организации. OrganizationType: организационная классификация на один из следующих типов: спортивные, правительственные военные, правительственные гражданские или политические партии. (обязательно) Национальность: Национальность организации, если она указана в документе. (Обязательно)


Вот пример кода, чтобы помочь:

private static void Main()
{
    const string str = "Organization: Name of a governmental, military or other organization. OrganizationType: Organization classification to one of the following types sports, governmental military, governmental civilian or political party. (required) Nationality: Organization nationality if mentioned in the document. (required)";

    var array = str.Split(':');
    var dictionary = array.ToDictionary(x => x[0], x => x[1]);

    foreach (var item in dictionary)
    {
        Console.WriteLine("{0}: {1}", item.Key, item.Value);
    }

    // Expecting to see the following output:

    // Organization: Name of a governmental, military or other organization.
    // OrganizationType: Organization classification to one of the following types sports, governmental military, governmental civilian or political party.
    // Nationality: Organization nationality if mentioned in the document. (required)
}

Вот визуальное объяснение того, что я пытаюсь сделать:

http://farm5.static.flickr.com/4081/4829708565_ac75b119a0_b.jpg

Ответы [ 3 ]

3 голосов
/ 26 июля 2010

Я бы сделал это в два этапа, сначала разделив на пары свойств, используя что-то вроде этого:

Regex.Split(input, "\s(?=[A-Z][A-Za-z]*:)")

это ищет любой пробел, за которым следует алфавитная строка с двоеточием.Буквенная строка должна начинаться с заглавной буквы.Затем он распадается на это пустое пространство.Это даст вам три строки в форме «PropertyName: PropertyValue».Разделить это первое двоеточие тогда довольно просто (лично я, вероятно, просто использовал бы подстроку и indexof, а не другое регулярное выражение, но вы звучите так, будто можете сделать это немного самостоятельно. Кричите, если вам нужна помощь со вторым разделением.

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

1 голос
/ 26 июля 2010

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

Organization: Name of a governmental, military or other organization.|OrganizationType: Organization classification to one of the following types: sports, governmental military, governmental civilian or political party. (required) |Nationality: Organization nationality if mentioned in the document. (required)

Обратите внимание на символ |, который указывает на конец пары. Тогда это просто случай использования очень специфического разделителя, который вряд ли будет использоваться в тексте описания, вместо двоеточия вы можете использовать 2 ::, так как один двоеточие может возникать в некоторых случаях, как предлагали другие , Это означает, что вам просто нужно сделать:

// split the string into rows
string[] rows = myString.Split('|');
Dictionary<string, string> pairs = new Dictionary<string, string>();
foreach (var r in rows)
{
    // split each row into a pair and add to the dictionary
    string[] split = Regex.Split(r, "::");
    pairs.Add(split[0], split[1]);
}

Вы можете использовать LINQ, как предлагали другие, выше это больше для удобочитаемости, чтобы вы могли видеть, что происходит.

Еще одна альтернатива - разработать какое-то пользовательское регулярное выражение, чтобы делать то, что вам нужно, но опять же вам нужно будет сделать много предположений о том, как текст описания будет отформатирован и т.д.

1 голос
/ 26 июля 2010

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

var resultDict = Regex.Split(input, @"(?<= [A-Z][a-zA-Z]+):")
                 .ToDictionary(a => a[0], a => a[1]);

(?<=...) - это положительное выражение для обратного просмотра , которое не «съедает» символы, поэтому из вывода удаляется только двоеточие.Протестировано с вашим вводом здесь .

[A-Z][a-zA-Z]+ означает: слово, начинающееся с заглавной буквы.

Обратите внимание, что, как и другие предлагали, "умнее"delimiter обеспечит более простой синтаксический анализ, как и экранирование (например, "::" или ":", когда вам необходимо использовать двоеточия. Хотя не уверен, что это варианты для вас, отсюда и решение с регулярными выражениями выше.

Редактировать

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

var splitArray = Regex.Split(input, @"(?<=( |^)[A-Z][a-zA-Z]+):|( )(?=[A-Z][a-zA-Z]+:)")
                            .Where(a => a.Trim() != "").ToArray();

Dictionary<string, string> resultDict = new Dictionary<string, string>();
for(int i = 0; i < splitArray.Count(); i+=2)
{
    resultDict.Add(splitArray[i], splitArray[i+1]);
}

Примечание: регулярное выражение становится немного сложным в этом сценарии. Как предложено в приведенной ниже цепочке, вы можете разделитьэто меньшими шагами. Также обратите внимание, что текущее регулярное выражение создает несколько пустых совпадений, которые я удаляю с помощью выражения Where выше. Цикл for не должен быть нуженЭд, если вам удастся заставить ToDictionary работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...