【问题标题】:Regular expression to find unescaped double quotes in CSV file正则表达式在 CSV 文件中查找未转义的双引号
【发布时间】:2009-10-21 15:51:28
【问题描述】:

什么是正则表达式来查找 CSV 文件中由双引号引起的列中包含的 2 个未转义双引号的集合?

不匹配:

"asdf","asdf"
"", "asdf"
"asdf", ""
"adsf", "", "asdf"

匹配:

"asdf""asdf", "asdf"
"asdf", """asdf"""
"asdf", """"

【问题讨论】:

  • 我在帖子中的换行符已关闭。现在有意义吗?
  • 是的。请参阅我的建议。

标签: regex csv


【解决方案1】:

试试这个:

(?m)""(?![ \t]*(,|$))

解释:

(?m)       // enable multi-line matching (^ will act as the start of the line and $ will act as the end of the line (i))
""         // match two successive double quotes
(?!        // start negative look ahead
  [ \t]*   //   zero or more spaces or tabs
  (        //   open group 1
    ,      //     match a comma 
    |      //     OR
    $      //     the end of the line or string
  )        //   close group 1
)          // stop negative look ahead

所以,用简单的英语:“匹配两个连续的双引号,前提是它们前面没有逗号或行尾,中间有可选的空格和制表符”.

(i) 除了是普通的字符串开始字符串结束元字符。

【讨论】:

  • 呃,这个不匹配 ` "asdf", "" `(不应该匹配)但不匹配 ` "asdf""asdf", "asdf" `(应该匹配)?
  • @Lucero:不,恰恰相反。它与"asdf", "" 中的双引号不匹配,但它与"asdf""asdf", "asdf" 中的双引号匹配。
  • 如果我们要找到像“asdf "something" asdf ", "asdf", ... 这样的非连续双引号,表达式会如何变化?
  • 这在 NodeJS 正则表达式引擎中不起作用。正如 NawaMan 下面解释的那样,也许解决方案实际上很大程度上取决于您使用的引擎。
【解决方案2】:

由于您的问题很复杂,解决方案取决于您使用的引擎。这是因为要解决它,您必须使用向后看和向前看,并且每个引擎都不相同。

我的答案是使用 Ruby 引擎。检查只是一个正则表达式,但我在这里列出了整个代码以便更好地解释它。

请注意,由于 Ruby RegEx 引擎(或我的知识),可选的前瞻/后视是不可能的。所以我需要逗号前后的空格问题。

这是我的代码:

orgTexts = [
    '"asdf","asdf"',
    '"", "asdf"',
    '"asdf", ""',
    '"adsf", "", "asdf"',
    '"asdf""asdf", "asdf"',
    '"asdf", """asdf"""',
    '"asdf", """"'
]

orgTexts.each{|orgText|
    # Preprocessing - Eliminate spaces before and after comma
    # Here is needed if you may have spaces before and after a valid comma
    orgText = orgText.gsub(Regexp.new('\" *, *\"'), '","')

    # Detect valid character (non-quote and valid quote)
    resText = orgText.gsub(Regexp.new('([^\"]|^\"|\"$|(?<=,)\"|\"(?=,)|(?<=\\\\)\")'), '-')
    # resText = orgText.gsub(Regexp.new('([^\"]|(^|(?<=,)|(?<=\\\\))\"|\"($|(?=,)))'), '-')
    # [^\"]       ===> A non qoute
    # |           ===> or
    # ^\"         ===> beginning quot
    # |           ===> or
    # \"$         ===> endding quot
    # |           ===> or
    # (?<=,)\"    ===> quot just after comma
    # \"(?=,)     ===> quot just before comma
    # (?<=\\\\)\" ===> escaped quot

    #  This part is to show the invalid non-escaped quots
    print orgText
    print resText.gsub(Regexp.new('"'), '^')

    # This part is to determine if there is non-escaped quotes
    # Here is the actual matching, use this one if you don't want to know which quote is un-escaped
    isMatch = ((orgText =~ /^([^\"]|^\"|\"$|(?<=,)\"|\"(?=,)|(?<=\\\\)\")*$/) != 0).to_s
    # Basicall, it match it from start to end (^...$) there is only a valid character

    print orgText + ": " + isMatch
    print 
    print ""
    print ""
} 

执行代码时打印:

"asdf","asdf"
-------------
"asdf","asdf": false


"","asdf"
---------
"","asdf": false


"asdf",""
---------
"asdf","": false


"adsf","","asdf"
----------------
"adsf","","asdf": false


"asdf""asdf","asdf"
-----^^------------
"asdf""asdf","asdf": true


"asdf","""asdf"""
--------^^----^^-
"asdf","""asdf""": true


"asdf",""""
--------^^-
"asdf","""": true

我希望我在这里给你一些想法,你可以使用其他引擎和语言。

【讨论】:

    【解决方案3】:
    ".*"(\n|(".*",)*)
    

    应该可以,我猜...

    【讨论】:

    • 请注意,.* 是贪婪的,可能会吃掉任意数量的字符,包括一些 ",因此例如 "adsf", "", "asdf" 也可以匹配。 (而且性能可能很差,因为即使在不匹配的情况下它也能匹配很多。)
    【解决方案4】:

    对于单行匹配:

    ^("[^"]*"\s*,\s*)*"[^"]*""[^"]*"
    

    或多行:

    (^|\r\n)("[^\r\n"]*"\s*,\s*)*"[^\r\n"]*""[^\r\n"]*"
    

    编辑/注意:根据所使用的正则表达式引擎,您可以使用lookbehinds 和其他东西来使正则表达式更精简。但这应该适用于大多数正则表达式引擎。

    【讨论】:

    • 嗨@Lucero,如果你知道它对你有用,那在NodeJS正则表达式引擎上不起作用:> var x = "\"field 1\", \"field 2 with \"里面的东西\",\"字段3\"";未定义 > x.match(/^("[^"]*"\s*,\s*)*"[^"]*""[^"]*"/) null
    • @giacecco,这里的问题要求在带引号的字符串中查找两个连续的双引号(""),这不是您的测试字符串中的内容。
    • 你是对的,我很抱歉。我对根据 CVS RFC 的事实感到困惑,双双引号实际上是有效的 CSV:这是双引号应该被转义的方式 tools.ietf.org/html/rfc4180#section-2 。一个类似的问题把我带到了这里,但不是最初的 Even Mien 有。
    【解决方案5】:

    试试这个正则表达式:

    "(?:[^",\\]*|\\.)*(?:""(?:[^",\\]*|\\.)*)+"
    

    这将匹配带有至少一对非转义双引号的任何带引号的字符串。

    【讨论】:

      猜你喜欢
      • 2013-10-01
      • 2014-08-01
      • 2011-03-11
      • 2013-05-10
      • 1970-01-01
      • 1970-01-01
      • 2011-05-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多