正则表达式以逗号分割,除非引用

时间:2010-11-11 01:29:25

标签: c# regex csv

除了用双引号括起来之外,在逗号(,)上拆分的正则表达式是什么?例如:

max,emily,john = ["max", "emily", "john"]

BUT

max,"emily,kate",john = ["max", "emily,kate", "john"]

希望在C#中使用:Regex.Split(string, "PATTERN-HERE");

感谢。

4 个答案:

答案 0 :(得分:14)

这样的情况通常需要除正则表达式之外的其他东西。它们很漂亮,但处理这种事情的模式比它们有用的更复杂。

您可以尝试这样的事情:

public static IEnumerable<string> SplitCSV(string csvString)
{
    var sb = new StringBuilder();
    bool quoted = false;

    foreach (char c in csvString) {
        if (quoted) {
            if (c == '"')
                quoted = false;
            else
                sb.Append(c);
        } else {
            if (c == '"') {
                quoted = true;
            } else if (c == ',') {
                yield return sb.ToString();
                sb.Length = 0;
            } else {
                sb.Append(c);
            }
        }
    }

    if (quoted)
        throw new ArgumentException("csvString", "Unterminated quotation mark.");

    yield return sb.ToString();
}

可能需要进行一些调整才能完全遵循CSV规范,但基本逻辑是合理的。

答案 1 :(得分:1)

对于CSV解析器来说,这是一个明确的案例,因此您应该使用.NET自己的CSV解析功能或cdhowie的解决方案。

纯粹是为了您的信息而是一个可行的解决方案,以下是使用Regex.Split()的正则表达式时必须经历的扭曲:

您可以使用正则表达式(请不要!

(?<=^(?:[^"]*"[^"]*")*[^"]*)  # assert that there is an even number of quotes before...
\s*,\s*                       # the comma to be split on...
(?=(?:[^"]*"[^"]*")*[^"]*$)   # as well as after the comma.

如果您的引用字符串从不包含转义引号,您不介意引号本身成为匹配的一部分。

这非常低效,读取和调试很痛苦,只能在.NET中运行,并且在转义引号上失败(至少如果你没有使用""来逃避单引号)。当然可以修改正则表达式 来处理它,但那时它将是完全可怕的。

答案 2 :(得分:0)

可能有点晚,但我希望我可以帮助别人

     String[] cols = Regex.Split("max, emily, john", @"\s*,\s*");
     foreach ( String s in cols ) {
        Console.WriteLine(s);
     }

答案 3 :(得分:0)

贾斯汀,重新提出这个问题,因为它有一个简单的正则表达式解决方案,没有提到。这种情况直接来自Match (or replace) a pattern except in situations s1, s2, s3 etc

这是我们简单的正则表达式:

"[^"]*"|(,)

交替的左侧匹配完整的"quoted strings"标签。我们将忽略这些匹配。右侧匹配并捕获第1组的逗号,我们知道它们是正确的逗号,因为它们与左侧的表达式不匹配。我们将这些逗号替换为SplitHere,然后我们将其分为SplitHere

此程序显示了如何使用正则表达式(请参阅online demo底部的结果):

using System;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
class Program
{
static void Main()  {
string s1 = @"max,""emily,kate"",john";
var myRegex = new Regex(@"""[^""]*""|(,)");
string replaced = myRegex.Replace(s1, delegate(Match m) {
    if (m.Groups[1].Value == "") return m.Value;
    else return "SplitHere";
    });
string[] splits = Regex.Split(replaced,"SplitHere");
foreach (string split in splits) Console.WriteLine(split);
Console.WriteLine("\nPress Any Key to Exit.");
Console.ReadKey();
} // END Main
} // END Program

参考

How to match (or replace) a pattern except in situations s1, s2, s3...