【问题标题】:Split string by ',' into array except ',' within ()将字符串按','拆分为数组,但()内的','除外
【发布时间】:2015-08-10 21:20:30
【问题描述】:

我有像

这样的字符串
"11,Standard(db=S,api=Standard),UI,1(db=1,api=STANDARD),Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36,1010,9999,1000,9998.0,,1"

我想用 char ',' 来分割它,但我不喜欢在 '()' 中包含 ','。请帮助如何在 c# 中拆分此类字符串。 忽略 () 中的 char ','。

输出应该是这样的:

   array of string = [ 
     "11", 
     "Standard(db=S,api=Standard)", 
     "UI", 
     "1(db=1,api=STANDARD)", 
     "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36", 
     "1010" 

等等

【问题讨论】:

  • 你需要一个解析器。您应该能够写一个,一次只读取一个字符并保持状态以查看您是否在() 范围内。
  • 任何像正则表达式的东西?
  • 嵌套x(a,b(c,d),e)的情况下怎么办?
  • 你最好显示你期望这个操作的输出......对于@DmitryBychenko的问题中提到的情况应该是什么?

标签: c# string split


【解决方案1】:

如果模式是always,您可以使用正则表达式来分割分隔符(逗号)而不是匹配标记。识别作为分隔符的逗号需要一个相对简单的方法:

",(?=[^\)]*(?:\(|$))"

演示:https://dotnetfiddle.net/GgboVn

解释:http://regexr.com/3bgfj

【讨论】:

  • 这匹配foo (,()) foo中的,
【解决方案2】:

这是一个解析器

public static IEnumerable<string> Parse(string Input)
{
    int depth = 0;
    StringBuilder Line = new StringBuilder();
    foreach (char item in Input)
    {
        if (depth == 0 && item == ',')
        {
            yield return Line.ToString();
            Line = new StringBuilder();
        }
        else
        {
            Line.Append(item);
            if (item == '(')
            {
                depth++;
            }
            if (item == ')')
            {
                depth--;
            }
        }
    }
    if (Line.Length > 0)
        yield return Line.ToString();
}

用途:

var result = Parse(input);

【讨论】:

  • 看来,StringBulider 将是 Linestring 更好的类型
  • @DmitryBychenko - 已更新。无论如何,对于这么短的字符串来说应该不会有那么大的区别
  • 实际上,我们不知道 实际字符串(或字符串)长度。通常,此类解析器用于扫描日志、日志等,以查找是否提到了 Mozilla。
【解决方案3】:

这是一个简单直接的解析器。不是防弹的,根据您的需要,它可能需要一些修改:

static void Main(string[] args)
    {
        var toSplit = "11,Standard(db=S,api=Standard),UI,1(db=1,api=STANDARD),Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36,1010,9999,1000,9998.0,,1";

        var list = new List<string>();
        var isInside = 0;
        var currentPart = string.Empty;

        for (int i = 0; i < toSplit.Length; i++)
        {
            var chr = toSplit[i];

            switch (chr)
            {
                case ',':
                    if(isInside == 0)
                    {
                        list.Add(currentPart);
                        currentPart = string.Empty;
                    }
                    break;

                case '(':                        
                    isInside++;
                    currentPart += chr;
                    break;

                case ')':
                    isInside--;
                    currentPart += chr;
                    break;

                default:
                    currentPart += chr;
                    break;
            }
        }

        foreach (var part in list)
        {
            Console.WriteLine(part);
        }

        Console.ReadLine();
    }

【讨论】:

  • 是的,我会使用StringBuilder 而不是字符串连接,但这几乎是 OP 应该做的。
  • 确实,@MarcinJuraszek,这将是第一个(也是强制性的)改进。
【解决方案4】:

这应该做你想做的事。它会将您在delimitter 的输入拆分到任何括号之外

static IEnumerable<string> SplitStringMyWay(string text, char delimitter)
{
    string[] internalItems = text.Split(delimitter);
    List<string> theItems = new List<string>();
     string newItem = string.Empty;
    int openParenthesis = 0;
     foreach (string item in internalItems)
    {
        if (openParenthesis != 0) newItem += ",";
         newItem += item;
        openParenthesis += GetCharCount('(', item);
        openParenthesis -= GetCharCount(')', item);
         if (openParenthesis == 0)
        {
            theItems.Add(newItem);
          newItem = string.Empty;
        }
    }
     return theItems;
}
static int GetCharCount(char value, string text)
{
    int count = 0;
    foreach (char character in text)
    {
        if (character == value)
        {
            count++;
        }
    }
     return count;
}

代码不是 testet,可能包含错误。如果您发现有人随时编辑我的答案

【讨论】:

    【解决方案5】:

    这是有效的

     var values = "11,Standard(db=S,api=Standard),UI,1(db=1,api=STANDARD),Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36,1010,9999,1000,9998.0,,1";
     var splitList = GetSplitList(values);
    
    
    
     public static List<string> GetSplitList(string values)
        {
            var splitList = new List<string>();
            var retValue = string.Empty;
            foreach (var value in values.Split(','))
            {
                if (!string.IsNullOrEmpty(retValue) && !value.Contains(")"))
                {
                    retValue += string.Format("{0},", value);
                    continue;
                }
                if (value.Contains("("))
                {
                    retValue += string.Format("{0},", value);
                    continue;
                }
                if (value.Contains(")"))
                {
                    retValue += value;
                    splitList.Add(retValue);
                    retValue = string.Empty;
                    continue;
                }
                splitList.Add(value);
            }
            return splitList;
    
        }
    

    【讨论】:

      【解决方案6】:

      IMO 最简单的方法是首先使用 ',' 拆分字符串,然后将字符串与 '(' 和 ')' 符号连接在一起:

      string value = @"11,Standard(db=S,api=Standard),UI,1(db=1,api=STANDARD),Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36,1010,9999,1000,9998.0,,1";
      
      List<string> list = new List<string>();
      
      string[] temp = value.Split(',');
      
      for (var i = 0; i < value.Split(',').Length; i++) { if (temp[i].Contains('(')) continue; if (temp[i].Contains(')')) { list.Add(temp[i - 1] + temp[i]); continue; } list.Add(temp[i]); }
      
      foreach (var item in list) Console.WriteLine(item);                
      

      输出:

      11
      Standard(db=S,api=Standard)
      UI
      1(db=1,api=STANDARD)
      

      附: 当然你也可以写你的解析器:

          static string[] MySplit(string dirty, char delimiter = ',', string ignoreInside = "()")
          {            
              StringBuilder sb = new StringBuilder();
              bool sectionStarted = false;
              List<string> result = new List<string>();
      
              for (int i = 0; i < dirty.Length; i++)
              {
                  if (!sectionStarted && dirty[i] == delimiter) 
                  {
                      result.Add(sb.ToString());
                      sb.Clear(); continue; 
                  }
      
                  if (ignoreInside.Contains(dirty[i])) sectionStarted = dirty[i] == ignoreInside[0];                 
                  sb.Append(dirty[i]);
              }
              return result.ToArray();
          }
      

      用法:var result = MySplit(value);

      输出与上例相同。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-12
        • 2016-04-01
        • 2012-02-22
        • 1970-01-01
        • 2011-01-10
        相关资源
        最近更新 更多