【问题标题】:Is this possible using regular expression这可以使用正则表达式吗
【发布时间】:2015-03-21 19:27:14
【问题描述】:

我使用的是 Python 2.7,我非常熟悉如何使用正则表达式以及如何在 Python 中使用它们。我想使用正则表达式用分号替换逗号分隔符。问题是用双引号包裹的数据应该保留嵌入的逗号。这是一个例子:

之前:

"3,14","1,000,000",hippo,"cat,dog,frog",plain text,"2,25"

之后:

"3,14";"1,000,000";hippo;"cat,dog,frog";plain text;"2,25"

是否有一个单一的正则表达式可以做到这一点?

【问题讨论】:

  • 你在读 csv 吗?
  • 不是直接重复,而是假设您要更改 CSV 的分隔符,这是您要查看的问题。
  • 您可以将 Python 的 csv 包与字符串一起使用。这将为您解决引号内的逗号问题。
  • 不是同一个问题,因为我要的是正则表达式解决方案

标签: python regex


【解决方案1】:

这是另一种避免测试所有字符串直到结束并在每次出现前先行的方式。这是一种(或多或少)\G re 模块的功能仿真。 该模式不是测试逗号之后的内容,而是查找逗号之前的项目(显然是逗号),并且以使每个完整匹配与先例连续的方式编写。

re.sub(r'(?:(?<=,)|^)(?=("(?:"")*(?:[^"]+(?:"")*)*"|[^",]*))\1,', r'\1;', s)

online demo

详情:

(?:          # ensures that results are contiguous 
    (?<=,)        # preceded by a comma (so, the one of the last result)
  |             # OR
    ^             # at the start of the string
)
(?= # (?=(a+))\1 is a way to emulate an atomic group: (?>a+)
    (                        # capture the precedent item in group 1
        "(?:"")*(?:[^"]+(?:"")*)*"  # an item between quotes
      |
        [^",]*               # an item without quotes
    )
) \1  # back-reference for the capture group 1
,

这种方式的优点是它减少了获得匹配的步骤数,并且无论之前的项目(参见 regex101 调试器),都提供了接近恒定的步骤数。原因是所有字符只匹配/测试一次。所以即使模式更长,它也更有效(特别是长线的增益增长)

原子组技巧只是为了减少最后一项(后面不跟逗号)失败之前的步骤数。

请注意,该模式处理引号之间带有转义引号(两个连续引号)的项目:"abcd""efgh""ijkl","123""456""789",foo

【讨论】:

  • 如何获得匹配数?我尝试使用 findall 和 finditer,但它们返回的计数比实际值少 1。 findall 不返回最后一个匹配项?
  • @panofish: 正常,只匹配逗号前的项,所以最后一项无法匹配!
  • @panofish:对不起,我忘记了引用项目以转义引用 """abc"" def" 开头的情况。已更正。
【解决方案2】:

您可以使用正则表达式拆分然后加入:

>>> ';'.join([i.strip(',') for i in re.split(r'(,?"[^"]*",?)?',s) if i])
'"3,14";"1,000,000";hippo;"cat,dog,frog";plain text;"2,25"'

【讨论】:

    【解决方案3】:

    这个正则表达式似乎可以完成这项工作

    ,(?=(?:[^"]*"[^"]*")*[^"]*\Z)
    

    改编自: How to match something with regex that is not between two special characters?

    并使用http://pythex.org/进行测试

    【讨论】:

      【解决方案4】:

      你可以使用:

      >>> s = 'foo bar,"3,14","1,000,000",hippo,"cat,dog,frog",plain text,"2,25"'
      >>> print re.sub(r'(?=(([^"]*"){2})*[^"]*$),', ';', s)
      foo bar;"3,14";"1,000,000";hippo;"cat,dog,frog";plain text;"2,25"
      

      RegEx Demo

      这将匹配逗号仅当它在引号之外通过匹配, 之后的偶数个引号。

      【讨论】:

        【解决方案5】:
        # Python 2.7
        import re
        
        text = '''
          "3,14","1,000,000",hippo,"cat,dog,frog",plain text,"2,25"
        '''.strip()
        
        print "Before: " + text
        print "After:  " + ";".join(re.findall(r'(?:"[^"]+"|[^,]+)', text))
        

        这会产生以下输出:

        Before: "3,14","1,000,000",hippo,"cat,dog,frog",plain text,"2,25"
        After:  "3,14";"1,000,000";hippo;"cat,dog,frog";plain text;"2,25"
        

        如果您需要更多自定义,可以修改此 here

        【讨论】:

        • 我喜欢 repl.it 网站!
        猜你喜欢
        • 2012-08-28
        • 2021-08-11
        • 1970-01-01
        • 1970-01-01
        • 2021-12-05
        • 2017-12-27
        • 2010-09-29
        • 2013-06-06
        相关资源
        最近更新 更多