非暴力强制正则表达式删除CSV列表中的逗号

时间:2014-01-29 18:18:38

标签: regex

我在这里要做的主要是学习正则表达式,以便我对它有更好的理解。我想要做的是使用正则表达式查找和替换只删除数字内的逗号。

我可以使用多个查找/替换模式来执行此操作,我也可以使用匹配大量数字和忽略逗号的强力方法来执行此操作,但是我想知道是否有某种方法可以将数字和逗号放入捕获组但忽略输出中的逗号。

以下是数字列表的示例:

"7,033.00","0.00","7,033.00","0.00","0.00","0.00","0.00","0.00","0.00","0.00",1,1,1,!!$,,"123,123,123.00","123,444,38.01"

所以我的'暴力'方法如下:

\"([0-9]+)[,]?([0-9]*)[,]?([0-9]*)[,]?([0-9]*[.]+[0-9]+)\"

这将占到999,999,999,999.00之前的任何数字。它包含四个捕获组$1$2$3$4,并将以我想要的格式输出我期望的任何数字。

使用替换$1$2$3$4

的有用输出示例
7033.00,0.00,7033.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,1,1,1,!!$,,123123123.00,12344438.01

我想做的是这样的事情(伪代码):

[\"]([0-9]+)([(?:,)[0-9]*][.]+[0-9]+)[\"]

这背后的想法是:

  1. 匹配第一个引号但忽略它
  2. 匹配一组数字并放入捕获组$ 1
  3. 匹配数字或逗号后跟一个句号和一个或多个数字并存储在捕获组中,将逗号留在捕获组之外。
  4. 匹配最后一个引号但忽略它
  5. 我一直在阅读和阅读,但似乎找不到按照我想要的方式忽略捕获组的一部分的方法。有什么建议或不能做到吗?

    两步法首先匹配逗号,然后删除引号,这也可能有效:

    (,)(?=([0-9]{2,3}[.,]))
    

2 个答案:

答案 0 :(得分:2)

好吧,regexr使用ECMAScript正则表达式,所以你可能会使用像

这样的东西
"|([0-9]),(?=[0-9])(?=(?:[^"]*"[^"]*")*[^"]*"[^"]*$)

并替换为$1

regexr demo

否则,使用PCRE,您可能会使用以下内容:

"|(?<=[0-9]),(?=[0-9])(?=(?:[^"]*"[^"]*")*[^"]*"[^"]*$)

并且无需替换,它使用外观来确保所讨论的逗号被[0-9]包围(ECMAScript目前不支持lookbehinds)。

regex101 demo

"匹配文字引号字符。

|表示OR,因此正则表达式匹配"([0-9]),(?=[0-9])(或(?<=[0-9]),(?=[0-9])

([0-9])是一个获取一位数的捕获组。

,匹配文字逗号。

(?=[0-9])是一个积极的前瞻,并确保逗号后跟一个数字,而不匹配数字本身。

(?<=[0-9])是一个积极的外观,并确保逗号前面有一个数字,同样没有匹配数字本身。

(?=(?:[^"]*"[^"]*")*[^"]*"[^"]*$)确保前面有奇数引号,这反过来意味着这将仅匹配引号内的逗号,假设没有不平衡或转义的引号。

答案 1 :(得分:1)

分两步:

首先删除引号内的所有逗号(即逗号后跟奇数引号。这甚至适用于转义引号,因为在CSV文件中,引号通过加倍来转义):

>>> import re
>>> s = '"7,033.00","0.00","7,033.00","0.00","0.00","0.00","0.00","0.00","0.00","0.00",1,1,1,!!$,,"123,123,123.00","123,444,38.01"'
>>> s = re.sub(r',(?!(?:[^"]*"[^"]*")*[^"]*$)', '', s)
>>> s
'"7033.00","0.00","7033.00","0.00","0.00","0.00","0.00","0.00","0.00","0.00",1,1,1,!!$,,"123123123.00","12344438.01"'

然后删除所有引号:

>>> s.replace('"', '')
'7033.00,0.00,7033.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,1,1,1,!!$,,123123123.00,12344438.01'