用于解析 CSV 的正则表达式

Posted

技术标签:

【中文标题】用于解析 CSV 的正则表达式【英文标题】:Regex for parsing CSV 【发布时间】:2012-07-01 00:04:47 【问题描述】:

我正在尝试编写一个从 CSV 文件中提取单个字段的正则表达式。

例如,如果在 CSV 文件中给出以下行:

123,    Bob    ,Bob, " Foo Bar ", "a, ""b"", c"

应该给出以下结果(不带引号):

'123'
'Bob'
'Bob'
' Foo Bar '
'a, "b", c'

请注意,除非在引号内,否则应修剪前导和尾随空格。

我不担心无效的 CSV 行,例如没有匹配右引号的开引号。根据上述规则,您可以放心地假设 CSV 文件完全有效。

如果单个正则表达式很困难,我也可以使用多个正则表达式。但我喜欢避免使用标准 C# 操作,除非它们简单而简短。 (我不想最终写很多代码。)

那么,有什么建议吗?

【问题讨论】:

为什么是正则表达式?只能用吗? 如果 CSV 完全有效,则引用字段中有换行符。 我认为“拆分”方法更适合这种情况。 我认为您关于 CSV 的“通用”概念是错误的。国际海事组织“通用”也会把报价还给你。 您正在尝试解决一个已经解决的问题 - 一次又一次 - 而且更优雅。您遇到的一些主要问题是您不了解“有效 CSV”是什么,并且确实有效的 CSV 数据集可以是多行的。 【参考方案1】:

我不会尝试编写自己的 csv 解析器,那里有很多可以为您完成这项工作。

http://www.filehelpers.com/ http://coding.abel.nu/2012/06/built-in-net-csv-parser/

【讨论】:

如果有可用的简单解决方案,我宁愿不必安装第三方库。但我会研究您第二个链接中提到的内置 Microsoft.VisualBasic.FileIO.TextFieldParser。【参考方案2】:

嗯,正则表达式可能存在许多陷阱和错误...尝试按照它对我有用的代码,它既甜美又简单...

Using Reader As New Microsoft.VisualBasic.FileIO.TextFieldParser("C:\MyFile.csv")

Reader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited

Dim MyDelimeters(0 To 0) As String
Reader.HasFieldsEnclosedInQuotes = False
Reader.SetDelimiters(","c)

Dim currentRow As String()
While Not Reader.EndOfData
    Try
        currentRow = Reader.ReadFields()
        Dim currentField As String
        For Each currentField In currentRow
            MsgBox(currentField)
        Next
    Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
        MsgBox("Line " & ex.Message &
        "is not valid and will be skipped.")
    End Try
End While
End Using

如果发现方便,标记为答案...;)

请在此处查看相同的implementation,,,

【讨论】:

我使用的是 C#,但我似乎找不到 Microsoft.VisualBasic.FileIO 命名空间。有没有我需要导入的参考资料? C# 你应该只添加“使用 System.IO;”这将为您提供读者和作者以及文件访问权限。 System.IO 没有 TextFieldParser 类。我在问我需要什么参考才能获得该课程。 哟,我有你的问题......更新了我的答案。 @Jigar 感谢您的帮助。 TextFieldParser 拥有我需要的一切......除了一件事:如果针对我上面的示例数据使用,字段“Foo Bar”返回“Foo Bar”而不是“Foo Bar”。但是如果我将 TrimWhiteSpace 设置为 false,那么像 Bob 这样的其他字段将不会修剪它们的空间......有什么想法吗?【参考方案3】:

我同意正则表达式不是“正确”的答案,但这是问题所要求的,我喜欢一个好的正则表达式挑战。

下面的模式是我的standard CSV parsing regex 的修改版本,它删除了空格并假设 CSV 符合您的要求。您的问题中唯一没有解决的部分是它不会删除转义/双引号。在模式之后给出了取消转义引号的示例。


当 CSV 文件/流的一个或多个行/记录被传递到下面的正则表达式时,它将为每个非空行/记录返回一个匹配项。每个匹配项都将包含一个名为 Value 的捕获组,其中包含该行/记录中的捕获值。

这是注释模式(测试它on Regexstorm.net):

(?<=\r|\n|^)(?!\r|\n|$)                       // Records start at the beginning of line (line must not be empty)
(?:                                           // Group for each value and a following comma or end of line (EOL) - required for quantifier (+?)
  [^\S\r\n]*                                  // Removes leading spaces
  (?:                                         // Group for matching one of the value formats before a comma or EOL
    "(?<Value>(?:[^"]|"")*)"|                 // Quoted value -or-
    (?<Value>[^,\r\n]+)|                      // Unquoted/open ended quoted value -or-
    (?<Value>)                                // Empty value before comma (before EOL is excluded by "+?" quantifier later)
  )
  [^\S\r\n]*                                  // Removes trailing spaces
  (?:,|(?=\r|\n|$))                           // The value format matched must be followed by a comma or EOL
)+?                                           // Quantifier to match one or more values (non-greedy/as few as possible to prevent infinite empty values)
(?:(?<=,)(?<Value>))?                         // If the group of values above ended in a comma then add an empty value to the group of matched values
(?:\r\n|\r|\n|$)                              // Records end at EOL

这是没有所有 cmets 或空格的原始模式。

(?<=\r|\n|^)(?!\r|\n|$)(?:[^\S\r\n]*(?:"(?<Value>(?:[^"]|"")*)"|(?<Value>[^,\r\n]+)|(?<Value>))[^\S\r\n]*(?:,|(?=\r|\n|$)))+?(?:(?<=,)(?<Value>))?(?:\r\n|\r|\n|$)

而且,这是 C# 转义版本。

String CSVPattern=
    @"(?<=\r|\n|^)(?!\r|\n|$)" +
    @"(?:" +
        @"[^\S\r\n]*" +
        @"(?:" +
            @"""(?<Value>(?:[^""]|"""")*)""|" +
            @"(?<Value>[^,\r\n]+)|" +
            @"(?<Value>)" +
        @")" +
        @"[^\S\r\n]*" +
        @"(?:,|(?=\r|\n|$))" +
    @")+?" +
    @"(?:(?<=,)(?<Value>))?" +
    @"(?:\r\n|\r|\n|$)";

关于如何使用正则表达式模式的示例(好吧,可以用这种模式替换的原始模式)可以在我对类似问题here、C# pad here 或here 的回答中找到。

注意:上面的示例包含取消转义/取消双引号的逻辑,如下所示:

if (Capture.Length == 0 || Capture.Index == Record.Index || Record.Value[Capture.Index - Record.Index - 1] != '\"')

    // No need to unescape/undouble quotes if the value is empty, the value starts
    // at the beginning of the record, or the character before the value is not a
    // quote (not a quoted value)
    Console.WriteLine(Capture.Value);

else

    // The character preceding this value is a quote
    // so we need to unescape/undouble any embedded quotes
    Console.WriteLine(Capture.Value.Replace("\"\"", "\""));

【讨论】:

我会为你在这个庞大的正则表达式中所做的工作量 +1 ! :P @SF Lee 谢谢!实际上,我一直担心这个答案会引起任何关注,因为担心它会因为作为正则表达式而被否决而被遗忘。至少现在它可以承受五次这样的投票而不会对声誉产生负面影响。 :)【参考方案4】:

您可以使用 .NET 框架中内置的 TextFieldParser 类。

为了在您的 C# 应用程序中使用该类,您需要在以下位置添加 Microsoft.VisualBasic.dll 的引用(假设您进行了默认设置安装)

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Microsoft.VisualBasic.dll

现在在你的 C# 类中有以下 using 语句:

using Microsoft.VisualBasic.FileIO

【讨论】:

以上是关于用于解析 CSV 的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

用于 CSV 拆分的正则表达式,包括多个双引号

用于在数字之前从 csv 中提取字符串的正则表达式

html 问Ben:使用Javascript Exec()正则表达式命令解析CSV字符串

正则表达式在csv中找到缺少的双引号

用于解析网页链接的正则表达式?

用于解析.net json Datetime 的 javascript 正则表达式