【问题标题】:Split string by commas ignoring any punctuation marks (including ',') in quotation marks用逗号分割字符串,忽略引号中的任何标点符号(包括',')
【发布时间】:2014-08-24 12:06:38
【问题描述】:

如何用逗号分割字符串(来自文本框)排除双引号中的字符串(不去掉引号),以及其他可能的标点符号标记(例如' . ' ' ; ' ' - ')?

例如如果有人在文本框中输入以下内容:

apple, orange, "baboons, cows", rainbow, "unicorns, gummy bears"

我怎样才能把上面的字符串拆分成下面的(比如说,拆分成一个列表)?

apple

orange

"baboons, cows"

rainbow

"Unicorns, gummy bears..."

感谢您的帮助!

【问题讨论】:

  • 如果处理 CSV 文件,最好使用现有的库,例如 LinqToCSV(还有其他库),而不是自己滚动。
  • 感谢@hatchet 的建议,但我实际上是在尝试向用户询问搜索词(以查询数据库)。
  • 注意:空格不是标点符号,但您的预期结果也会删除空格。不要在你的代码中忘记这一点。并且至少有一个当前答案假设 每个 逗号后跟一个空格,并且实际上在 ", " 上拆分。请注意,这不适用于apple,orange。另外,当" 没有出现在逗号附近时,apple,orange"banana,peach"almond,kiwi 应该如何拆分?
  • 或者......既然你说这是搜索词,为什么要求用户输入逗号呢?用户是否会期望搜索a b c 会搜索到那个确切的短语,而用户必须输入a, b, c 来代替搜索这些词?这取决于用户;您可能应该仔细检查这确实是您的用户所期望的,或者更改逻辑。
  • 非常感谢您的建议和建议,@hvd!

标签: c# regex string split comma


【解决方案1】:

你可以试试下面的正则表达式,它使用了积极的前瞻,

string value = @"apple, orange, ""baboons, cows"", rainbow, ""unicorns, gummy bears""";
string[] lines = Regex.Split(value, @", (?=(?:""[^""]*?(?: [^""]*)*))|, (?=[^"",]+(?:,|$))");

foreach (string line in lines) {
Console.WriteLine(line);
}

输出:

apple
orange
"baboons, cows"
rainbow
"unicorns, gummy bears"

IDEONE

【讨论】:

  • 感谢您的帮助,@Avinash!
  • 如果要根据,.:-进行拆分,则使用字符类[,.:-] (?=(?:""[^""]*?(?: [^""]*)*))|[,.:-] (?=[^"",]+(?:,|$))
  • 不用担心,@Avinash。我正在尝试所有这些不错的建议,看看哪一个更适合我的情况。
【解决方案2】:

试试这个:

Regex str = new Regex("(?:^|,)(\"(?:[^\"]+|\"\")*\"|[^,]*)", RegexOptions.Compiled);

foreach (Match m in str.Matches(input))
{
    Console.WriteLine(m.Value.TrimStart(','));
}

你也可以试试看FileHelpers

【讨论】:

  • 谢谢@R.T.但仅当引号紧跟在逗号之后(即不被空格分隔)时才有效。抱歉,我不熟悉正则表达式!
【解决方案3】:

很像 CSV 解析器,而不是正则表达式,您可以循环遍历每个字符,如下所示:

public List<string> ItemStringToList(string inputString)
{  
    var itemList   = new List<string>();
    var currentIem = "";
    var quotesOpen = false;

    for (int i = 0; i < inputString.Length; i++)
    {
        if (inputString[i] == '"')
        {
            quotesOpen = !quotesOpen;
            continue;
        }

        if (inputString[i] == ',' && !quotesOpen)
        {
            itemList.Add(currentIem);
            currentIem = "";
            continue;
        }

        if (currentIem == "" && inputString[i] == ' ') continue;
        currentIem += inputString[i];
    }

    if (currentIem != "") itemList.Add(currentIem);

    return itemList;
}

示例测试用法:

var test1 = ItemStringToList("one, two, three");
var test2 = ItemStringToList("one, \"two\", three");
var test3 = ItemStringToList("one, \"two, three\"");
var test4 = ItemStringToList("one, \"two, three\", four, \"five six\", seven");
var test5 = ItemStringToList("one, \"two, three\", four, \"five six\", seven");
var test6 = ItemStringToList("one, \"two, three\", four, \"five six, seven\"");
var test7 = ItemStringToList("\"one, two, three\", four, \"five six, seven\"");

如果您想要更快的字符连接,可以将其更改为使用 StringBuilder。

【讨论】:

  • 不错的一个。顺便说一句:我会使用iterator methodyield 而不是itemList.Add。这将使您摆脱itemList(更少的代码)并免费延迟执行作为额外的好处。
  • 感谢您的帮助,@WholsRich!
【解决方案4】:

试试这个,如果你想用空格分割,只要在 (' ') 中放一个空格,它就会以多种方式工作。

  namespace LINQExperiment1
  {
  class Program
  {
  static void Main(string[] args)
  {
   string[] sentence = new string[] { "apple", "orange", "baboons  cows", " rainbow", "unicorns  gummy bears" };

  Console.WriteLine("option 1:"); Console.WriteLine("————-");
  // option 1: Select returns three string[]’s with
  // three strings in each.
  IEnumerable<string[]> words1 =
  sentence.Select(w => w.Split(' '));
  // to get each word, we have to use two foreach loops
  foreach (string[] segment in words1)
  foreach (string word in segment)
  Console.WriteLine(word);
  Console.WriteLine();
  Console.WriteLine("option 2:"); Console.WriteLine("————-");
  // option 2: SelectMany returns nine strings
  // (sub-iterates the Select result)
  IEnumerable<string> words2 =
  sentence.SelectMany(segment => segment.Split(','));
  // with SelectMany we have every string individually
  foreach (var word in words2)
  Console.WriteLine(word);
  // option 3: identical to Opt 2 above written using
  // the Query Expression syntax (multiple froms)
  IEnumerable<string> words3 =from segment in sentence
  from word in segment.Split(' ')
  select word;
   }
  }
 }

【讨论】:

  • 感谢您的帮助,@Midhun!
  • @MooMooCoding 欢迎=D
【解决方案5】:

这比我想象的要棘手,我认为这是一个很好的实际问题。

以下是我为此提出的解决方案。我不喜欢我的解决方案的一件事是必须添加双引号,另一件事是变量的名称:p:

internal class Program
{
    private static void Main(string[] args)
    {

        string searchString =
            @"apple, orange, ""baboons, cows. dogs- hounds"", rainbow, ""unicorns, gummy bears"", abc, defghj";

        char delimeter = ',';
        char excludeSplittingWithin = '"';

        string[] splittedByExcludeSplittingWithin = searchString.Split(excludeSplittingWithin);

        List<string> splittedSearchString = new List<string>();

        for (int i = 0; i < splittedByExcludeSplittingWithin.Length; i++)
        {
            if (i == 0 || splittedByExcludeSplittingWithin[i].StartsWith(delimeter.ToString()))
            {
                string[] splitttedByDelimeter = splittedByExcludeSplittingWithin[i].Split(delimeter);
                for (int j = 0; j < splitttedByDelimeter.Length; j++)
                {
                    splittedSearchString.Add(splitttedByDelimeter[j].Trim());
                }
            }
            else
            {
                splittedSearchString.Add(excludeSplittingWithin + splittedByExcludeSplittingWithin[i] +
                                         excludeSplittingWithin);
            }
        }

        foreach (string s in splittedSearchString)
        {
            if (s.Trim() != string.Empty)
            {
                Console.WriteLine(s);
            }
        }
        Console.ReadKey();
    }
}

【讨论】:

  • 感谢您的帮助,@HakuKalay。看到不同的人对同一个问题采取不同的方法,这很好,也很有意义。一些解决方案背后的理论也可以用于解决其他类型的问题!
【解决方案6】:

另一种正则表达式解决方案:

private static IEnumerable<string> Parse(string input)
{
  // if used frequently, should be instantiated with Compiled option
  Regex regex = new Regex(@"(?<=^|,\s)(\""(?:[^\""]|\""\"")*\""|[^,\s]*)");

  return regex.Matches(inputData).Where(m => m.Success);
}

【讨论】:

  • 感谢您的帮助,@Igor!
猜你喜欢
  • 2017-04-07
  • 1970-01-01
  • 2012-05-23
  • 2018-04-14
  • 2020-04-05
  • 1970-01-01
  • 2013-04-02
  • 2013-10-14
  • 1970-01-01
相关资源
最近更新 更多