繁体   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