【问题标题】:Regex to to parse csv with nested quotes [duplicate]正则表达式来解析带有嵌套引号的csv [重复]
【发布时间】:2011-10-30 19:37:30
【问题描述】:

可能重复:
C#, regular expressions : how to parse comma-separated values, where some values might be quoted strings themselves containing commas
regex to parse csv

我知道这个问题已经问过很多次了,但答案却不尽相同;我很困惑。

我的行是:

1,3.2,BCD,"qwer 47"" ""dfg""",1

可选引用和双引号 MS Excel 标准。 (数据:qwer 47" "dfg"是这样表示的"qwer 47"" ""dfg"""。)

我需要一个正则表达式。

【问题讨论】:

  • 说真的.. 提供一些所需的输出。我不知道你想要达到什么目的。
  • 这是我 csv 中的一行,我需要验证或匹配
  • 数据:qwer 47" "dfg" 是这样表示的 "qwer 47"" ""dfg"""(MS excel 标准)
  • 我认为意图很明确,但为什么要使用正则表达式而不是 CSV 解析器?
  • 但是你想做什么?您需要指定哪些值是可接受的,哪些不是。

标签: regex csv


【解决方案1】:

好的,您已经从 cmets 看到 regex 是 所以 不是正确的工具。但如果你坚持,这里是:

此正则表达式可在 Java(或 .NET 和其他支持所有格量​​词和详细正则表达式的实现)中工作:

^            # Start of string
(?:          # Match the following:
 (?:         #  Either match
  [^",\n]*+  #   0 or more characters except comma, quote or newline
 |           #  or
  "          #   an opening quote
  (?:        #   followed by either
   [^"]*+    #    0 or more non-quote characters
  |          #   or
   ""        #    an escaped quote ("")
  )*         #   any number of times
  "          #   followed by a closing quote
 )           #  End of alternation
 ,           #  Match a comma (separating the CSV columns)
)*           # Do this zero or more times.
(?:          # Then match
 (?:         #  using the same rules as above
  [^",\n]*+  #  an unquoted CSV field
 |           #  or a quoted CSV field
  "(?:[^"]*+|"")*"
 )           #  End of alternation
)            # End of non-capturing group
$            # End of string

Java 代码:

boolean foundMatch = subjectString.matches(
    "(?x)^         # Start of string\n" +
    "(?:           # Match the following:\n" +
    " (?:          #  Either match\n" +
    "  [^\",\\n]*+ #   0 or more characters except comma, quote or newline\n" +
    " |            #  or\n" +
    "  \"          #   an opening quote\n" +
    "  (?:         #   followed by either\n" +
    "   [^\"]*+    #    0 or more non-quote characters\n" +
    "  |           #   or\n" +
    "   \"\"       #    an escaped quote (\"\")\n" +
    "  )*          #   any number of times\n" +
    "  \"          #   followed by a closing quote\n" +
    " )            #  End of alternation\n" +
    " ,            #  Match a comma (separating the CSV columns)\n" +
    ")*            # Do this zero or more times.\n" +
    "(?:           # Then match\n" +
    " (?:          #  using the same rules as above\n" +
    "  [^\",\\n]*+ #  an unquoted CSV field\n" +
    " |            #  or a quoted CSV field\n" +
    "  \"(?:[^\"]*+|\"\")*\"\n" +
    " )            #  End of alternation\n" +
    ")             # End of non-capturing group\n" +
    "$             # End of string");

请注意,您不能假定 CSV 文件中的每一行都是完整的行。您可以在 CSV 行中包含换行符(只要包含换行符的列括在引号中)。这个正则表达式知道这一点,但如果你只给它部分行它会失败。这也是您真正需要 CSV 解析器来验证 CSV 文件的另一个原因。这就是解析器所做的。如果您控制自己的输入并且知道在 CSV 字段中永远不会有换行符,那么您可能会侥幸逃脱,但只有这样。

【讨论】:

  • 如何用这个正则表达式读取 CSV 字段?
  • 根据我的经验,这种类型的正则表达式可能会导致灾难性的回溯regular-expressions.info/catastrophic.html 并使您的系统崩溃。如果您缺少带引号的字符串的最后一个引号(即 csv 行被截断/损坏),就会出现这种情况
【解决方案2】:

我已经有一段时间没有做 Java 了,所以这里有一个伪代码来做这件事。您可以将其用作接受代表 csv 行的字符串的函数。

1. Split the row by "'" delimiter into an array of strings. (method might be called string.split())
2. Iterate through the array (cells).
    3. If the current string (cell) contains a double quote:
        4. If it doesn't start with a quote - return false; else remove that quote
        5. If it doesn't end with a quote - return false; else remove that quote
        6. Iterate through the remaining characters of the string
            7. If a quote is found, check if the next character is also a quote - if it is not - return false
        7. End character iteration
    8. End if
9. End array iteration
10. Return true

【讨论】:

  • 嗨,niko,这是我试图避免的。我想一次性验证它
  • regex 几乎不是“一次性”——它很可能比这段代码更昂贵。如果您需要单线,请将其用作您要调用的方法。您对代码长度或类似限制有限制吗?
  • 据我了解,正则表达式的字符串解析速度更快
  • 对于您需要的复杂正则表达式,几乎可以保证它比专门的编码解决方案慢。正则表达式仍然必须遍历字符串,并且必须遍历自身并使用复杂的规则来匹配模式。在这段代码中,我们并没有真正匹配任何东西——我们正在寻找一个特定的字符。正则表达式将是一个矫枉过正。
  • 在引号中有逗号的情况下会失败。 :-)
【解决方案3】:

我使用这篇博客文章中的正则表达式,这与您尝试解决的问题大致相同。

在这里查看:http://www.kimgentes.com/worshiptech-web-tools-page/2008/10/14/regex-pattern-for-parsing-csv-files-with-embedded-commas-dou.html

简而言之^(("(?:[^"]|"")*"|[^,]*)(,("(?:[^"]|"")*"|[^,]*))*)$

【讨论】:

  • 我经历过,你能解释一下吗。
  • 这是不正确的。它允许像 "lkj"""lkjlkj"""""" 这样的字符串以及许多其他不应匹配的字符串。
  • 你是对的,谢谢。我用它来解析(所以没关系),他需要验证。
猜你喜欢
  • 2011-03-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-05
  • 1970-01-01
  • 1970-01-01
  • 2016-07-02
  • 2011-06-27
  • 1970-01-01
相关资源
最近更新 更多