2017-01-31 4 views
-3

Мне нужно создать синтаксический анализатор строк на C#. строка должна быть разобрана родитель-потомок связи, строка как:Очистить быстрый и эффективный способ разбора строки в C#

Water, Bulgur Wheat (29%), Sweetened Dried Cranberries (5%) (Sugar, Cranberries), Sunflower Seeds (3%), Onion (3%), Green Lentils (2%), Palm Oil, Flavourings (contain Barley), Lemon Juice Powder (<2%) (Maltodextrin, Lemon Juice Concentrate), Ground Spices (<2%) (Paprika, Black Pepper, Cinnamon, Coriander, Cumin, Chilli Powder, Cardamom, Pimento, Ginger), Dried Herbs (<2%) (Coriander, Parsley, Mint), Dried Garlic (<2%), Salt, Maltodextrin, Onion Powder (<2%), Cumin Seeds, Dried Lemon Peel (<2%), Acid (Citric Acid) 

Я знаю, что я мог бы пойти полукокса на гольца и в конечном итоге найти свой путь через это, но то, что это самый простой способ, чтобы получить эту информацию.

Ожидаемый выход: -

enter image description here

+0

@Anand: спасибо за ответ. Я заменил все скобки круглыми скобками и сломал его в древовидной структуре – Supreet

+0

Последняя часть моего комментария все еще остается без ответа. Что ожидается от этого? Скажите, что вы передаете эту строку функции, чего вы ожидаете? – A3006

+0

@Anand: найдите ожидаемый результат – Supreet

ответ

0
public static string ParseString(string input) 
{ 
    StringBuilder sb = new StringBuilder(); 
    bool skipNext = false; // used to skip spaces after commas 
    foreach (char c in input) 
    { 
     if (!skipNext) 
     { 
      switch (c) 
      { 
       case '(': 
        sb.Append("\n\t"); 
        break; 
       case ',': 
        sb.Append("\n"); 
        skipNext = true; 
        break; 
       case ')': 
        sb.Append("\n"); 
        break; 
       default: 
        sb.Append(c); 
        break; 
      } 
     } 
     else 
     { 
      skipNext = false; 
     } 
    } 

    return sb.ToString(); 
} 

Это должно вам начать работу. Он не обрабатывает скобки, которые не обозначают детей.

0

После просмотра данных, опубликованных (Вода, Булгар ...), одна проблема будет различать/разделять каждый отдельный предмет: 1 Вода, 2 Булгар .., 3 Подслащенная.

Разделение по запятой "," не будет работать, поскольку в некоторых скобках есть запятые "()" as (Sugar, Cranberries). Эти предметы (Сахар, Клюква) являются SUB-элементами для Sweetened Dried Cranberries ... поэтому разделение строки на запятые не будет работать.

Из ваших данных я хотел бы рассмотреть возможность изменения его формата, чтобы удовлетворить эту ситуацию. Простым изменением было бы изменить разделитель запятой между подгруппами на что-то еще ... Тире «-» может работать.

Ниже приведен код Regex. Это в основном изменяет каждую запятую "," между открытой и закрывающейся скобкой "()" до тире "-". Это позволит разделить на запятые, чтобы идентифицировать каждый элемент.

private static string ReplaceCommaBetweenParens(string inString) { 
    string pattern = @"(?<=\([^\)]*)+,(?!\()(?=[^\(]*\))"; 
    return Regex.Replace(inString, pattern, "-"); 
} 

Приведенный выше код не довольно, и я получил этот код где-то еще, и жаль, что я мог бы сайт автора оригинала. Я приветствую всех поклонников Regex, чтобы критиковать образец. Я не уверен, как вы это сделаете, используя обычный метод (ы) строки (split/indexof), чтобы выполнить это. Я уверен, что это займет несколько шагов. Хороший пример того, насколько полезным может быть Regex в некоторых ситуациях. Это может быть уродливо, но это работает безумно быстро. К счастью, вышеупомянутый критический код (Regex) не поможет многого после этого шага.

После того, как это изменение было сделано, процесс довольно прямой, чтобы отложить ваш выход по мере необходимости. Код ниже читает каждую строку из DataTable. Каждая строка может содержать 1 или более элементов, разделенных запятыми ",". Код проходит через каждую строку, анализируя элементы в строке. Я сделал простой класс для хранения предметов; однако код начинен правильным выходом, если класс не нужен. Надеюсь это поможет.

Простой класс для хранения отдельных элементов

class Ingredient { 

    int ID { get; set; } 
    string Name { get; set; } 
    string Percent { get; set; } 
    List<string> Ingredients { get; set; } 

    public Ingredient(int id, string name, string pct, List<string> ingredients) { 
    ID = id; 
    Name = name; 
    Percent = pct; 
    Ingredients = ingredients; 
    } 

    public override string ToString() { 
    StringBuilder sb = new StringBuilder(); 
    sb.Append(ID + "\t" + Name + " " + Percent + Environment.NewLine); 
    foreach (string s in Ingredients) { 
     sb.Append("\t\t" + s + Environment.NewLine); 
    } 
    return sb.ToString(); 
    } 
} 

код использовать указанный класс

static string ingredients = "Water, Bulgur Wheat(29%), Sweetened Dried Cranberries(5%) (Sugar, Cranberries)," + 
           " Sunflower Seeds(3%), Onion(3%), Green Lentils(2%), Palm Oil, Flavourings (contain Barley)," + 
           " Lemon Juice Powder(<2%) (Maltodextrin, Lemon Juice Concentrate)," + 
           " Ground Spices(<2%) (Paprika, Black Pepper, Cinnamon, Coriander, Cumin, Chilli Powder, Cardamom, Pimento, Ginger)," + 
           " Dried Herbs(<2%) (Coriander, Parsley, Mint), Dried Garlic(<2%), Salt, Maltodextrin, Onion Powder(<2%)," + 
           " Cumin Seeds, Dried Lemon Peel(<2%), Acid(Citric Acid)"; 

static List<Ingredient> allIngredients; 

static void Main(string[] args) { 
    allIngredients = ParseString(ingredients); 
    foreach (Ingredient curIngredient in allIngredients) { 
    Console.Write(curIngredient.ToString()); 
    } 
    Console.ReadLine(); 
} 

private static List<Ingredient> ParseString(string inString) { 
    List<Ingredient> allIngredients = new List<Ingredient>(); 
    string temp = ReplaceCommaBetweenParens(ingredients); 
    string[] allItems = temp.Split(','); 
    int count = 1; 
    foreach (string curItem in allItems) { 
    if (curItem.Contains("(")) { 
     allIngredients.Add(ParseItem(curItem, count)); 
    } 
    else { 
     allIngredients.Add(new Ingredient(count, curItem.Trim(), "", new List<string>())); 
     //Console.WriteLine(count + "\t" + curItem.Trim()); 
    } 
    count++; 
    } 
    return allIngredients; 
} 

private static Ingredient ParseItem(string item, int count) { 
    string pct = ""; 
    List<string> items = new List<string>(); 
    int firstParenIndex = item.IndexOf("("); 
    //Console.Write(count + "\t" + item.Substring(0, firstParenIndex).Trim()); 

    Regex expression = new Regex(@"\((.*?)\)"); 
    MatchCollection matches = expression.Matches(item); 
    bool percentPresent = true; 
    foreach (Match match in matches) { 
    if (match.ToString().Contains("%")) { // <-- if the string between parenthesis does not contain "%" - move to next line, otherwise print on same line 
     //Console.WriteLine(" " + match.ToString().Trim()); 
     pct = match.ToString().Trim(); 
     percentPresent = false; 
    } 
    else { 
     if (percentPresent) { 
     //Console.WriteLine(); 
     } 
     items = GetLastItems(match.ToString().Trim()); 
    } 
    } 
    return new Ingredient(count, item.Substring(0, firstParenIndex).Trim(), pct, items); 
} 

private static List<string> GetLastItems(string inString) { 
    List<string> result = new List<string>(); 
    string temp = inString.Replace("(", ""); 
    temp = temp.Replace(")", ""); 
    string[] allItems = temp.Split('-'); 
    foreach (string curItem in allItems) { 
    //Console.WriteLine("\t\t" + curItem.Trim()); 
    result.Add(curItem.Trim()); 
    } 
    return result; 
} 

private static string ReplaceCommaBetweenParens(string inString) { 
    string pattern = @"(?<=\([^\)]*)+,(?!\()(?=[^\(]*\))"; 
    return Regex.Replace(inString, pattern, "-"); 
} 
+0

Спасибо большое :) – Supreet

Смежные вопросы