簡體   English   中英

在 C# 中解析字符串的清潔最快和有效的方法

[英]Clean fastest & efficient way to parse a string in 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)

我知道我可以逐個字符地查找並最終找到通過它的方式,但是獲取此信息的最簡單方法是什么。

預期輸出:-

在此處輸入圖片說明

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

這應該讓你開始。 它不處理不表示孩子的括號。

在查看發布的數據(水,保加利亞……)后,一個問題將區分/分離每個單獨的項目:1 水,2 保加利亞……,3 加糖。

拆分逗號“,”將不起作用,因為某些括號“()”內有逗號,如 (Sugar, Cranberries)。 這些項目(糖、蔓越莓)是甜蔓越莓干的子項目......所以用逗號分割字符串是行不通的。

根據您給定的數據,我會考慮更改其格式以適應這種情況。 一個簡單的更改是將子組之間的逗號分隔符更改為其他內容……破折號“-”可能會起作用。

下面的正則表達式代碼就是這樣做的。 這基本上將每個逗號“,”在左括號和右括號“()”之間更改為破折號“-”。 這將允許用逗號分隔來標識每個項目。

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

上面的代碼並不漂亮,我從其他地方得到了這段代碼,希望能找到原作者的網站。 我歡迎所有正則表達式愛好者批評該模式。 我不確定您將如何使用常規字符串方法(split/indexof)來完成此操作。 我相信這需要幾個步驟。 正則表達式在某些情況下是多么有用的一個很好的例子。 它可能很丑,但它的工作速度非常快。 幸運的是,在這一步之后,上面的神秘代碼 (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, "-");
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM