正则表达式检测 csv 文件中包含逗号的数字的无效行
Regex to detect invalid rows in csv file with numbers containing commas
下面是我文件中的示例行。每行有 3 个数字字段。有些数字有逗号并被引用。有些行有多余的逗号(文件是从 pdf 中提取表格数据输出的)我正在尝试检测并删除有效的 3 字段匹配左侧或右侧的多余空字段。
"3,33","4,03","12,23" - valid
2,,"3,23" - valid
,,"3,13",1,6 - invalid - remove first 2 commas
,1,,"3,987", - invalid - remove comma at beginning and end
这就是我的 - (([0-9,]*,){3})
但是正在努力找出如何匹配可能包含或不包含数字的引号。
基本上我不清楚如果检测到报价然后如何寻找结束报价,如果没有,则不寻找任何结束报价。
感谢您的帮助!
(我正在使用 sublimetext 3 进行搜索和替换,但如果需要,我可以在 Python 中进行。)
如果您使用 python,我建议使用 csv 库:
data = '''"3,33","4,03","12,23"
2,,"3,23"
,,"3,13",1,6
,1,,"3,987",'''.split('\n')
import csv
for row in csv.reader(data):
print(row)
输出:
['3,33', '4,03', '12,23']
['2', '', '3,23']
['', '', '3,13', '1', '6']
['', '1', '', '3,987', '']
但是如果你想做一个正则表达式,你可以:
(([0-9]*)|("[0-9,]*"),){3}
使用垂直管道 |对于“或”,所以要么是数字序列 [0-9]*
,要么是用引号括起来的数字和逗号 "[0-9,]*"
.
看来您的字段内容可能是:
- 空
- 一个整数
\d+
- 带引号的十进制数
"\d+,\d+"
这可以表示为(|\d+|"\d+,\d+")
。您需要其中三个,以逗号分隔:
(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+")
(你可以使用 (|\d+|"\d+,\d+")(,(|\d+|"\d+,\d+")){2}
来搞乱重复,但同样的事情重复三次更容易理解)。
请注意,这只是假设最后一个字段为“空”,因为这足以符合您的定义。所以我们需要把它锚定到行首和行尾:
^(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+")$
这将只匹配有效行。
根据你的解释,开头和结尾可能会有多余的逗号,但没有其他字符,所以应该是:
^,*(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+"),*$
这现在匹配所有行,但没有给您真正关心的内容,即中间的“好”部分。为此,您可以使用一个组(使用括号)。不过,我们已经在使用组,对于 |
替代方案,因此我们需要添加 ?:
以使它们成为非捕获:
^,*(?:|\d+|"\d+,\d+"),(?:|\d+|"\d+,\d+"),(?:|\d+|"\d+,\d+"),*$
现在,您可以将您关心的部分包装在捕获组中,为我们提供最终的正则表达式:
^,*((?:|\d+|"\d+,\d+"),(?:|\d+|"\d+,\d+"),(?:|\d+|"\d+,\d+")),*$
在正则表达式模式下搜索和替换,使用此正则表达式进行搜索,</code> 用于替换值。</p>
<p>如果多个字段为空,则可能有多种可能的解决方案。如果您的三个值中的第一个和最后一个值永远不会为空,您可以相应地调整正则表达式。如果是,这将选择 <em>one</em> 一组有效值,这可能不是您想要的。例如,如果您有:</p>
<pre><code>,,1,"2,3",,
那么 ,1,"2,3
(empty, 1, 2.3) 和 1,"2,3",
(1, 2.3, empty) 都是可能的解决方案。默认情况下,您将获得第二个结果,因为 *
是贪心的,即第一个 ,*
将尝试“吃掉”尽可能多的逗号而不会使匹配失败。您可以像这样添加一个问号:,*?
使匹配“懒惰”或“非贪婪”,然后它只会根据需要使用尽可能多的逗号(产生第一个结果)。
下面是我文件中的示例行。每行有 3 个数字字段。有些数字有逗号并被引用。有些行有多余的逗号(文件是从 pdf 中提取表格数据输出的)我正在尝试检测并删除有效的 3 字段匹配左侧或右侧的多余空字段。
"3,33","4,03","12,23" - valid
2,,"3,23" - valid
,,"3,13",1,6 - invalid - remove first 2 commas
,1,,"3,987", - invalid - remove comma at beginning and end
这就是我的 - (([0-9,]*,){3})
但是正在努力找出如何匹配可能包含或不包含数字的引号。
基本上我不清楚如果检测到报价然后如何寻找结束报价,如果没有,则不寻找任何结束报价。 感谢您的帮助!
(我正在使用 sublimetext 3 进行搜索和替换,但如果需要,我可以在 Python 中进行。)
如果您使用 python,我建议使用 csv 库:
data = '''"3,33","4,03","12,23"
2,,"3,23"
,,"3,13",1,6
,1,,"3,987",'''.split('\n')
import csv
for row in csv.reader(data):
print(row)
输出:
['3,33', '4,03', '12,23']
['2', '', '3,23']
['', '', '3,13', '1', '6']
['', '1', '', '3,987', '']
但是如果你想做一个正则表达式,你可以:
(([0-9]*)|("[0-9,]*"),){3}
使用垂直管道 |对于“或”,所以要么是数字序列 [0-9]*
,要么是用引号括起来的数字和逗号 "[0-9,]*"
.
看来您的字段内容可能是:
- 空
- 一个整数
\d+
- 带引号的十进制数
"\d+,\d+"
这可以表示为(|\d+|"\d+,\d+")
。您需要其中三个,以逗号分隔:
(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+")
(你可以使用 (|\d+|"\d+,\d+")(,(|\d+|"\d+,\d+")){2}
来搞乱重复,但同样的事情重复三次更容易理解)。
请注意,这只是假设最后一个字段为“空”,因为这足以符合您的定义。所以我们需要把它锚定到行首和行尾:
^(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+")$
这将只匹配有效行。
根据你的解释,开头和结尾可能会有多余的逗号,但没有其他字符,所以应该是:
^,*(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+"),(|\d+|"\d+,\d+"),*$
这现在匹配所有行,但没有给您真正关心的内容,即中间的“好”部分。为此,您可以使用一个组(使用括号)。不过,我们已经在使用组,对于 |
替代方案,因此我们需要添加 ?:
以使它们成为非捕获:
^,*(?:|\d+|"\d+,\d+"),(?:|\d+|"\d+,\d+"),(?:|\d+|"\d+,\d+"),*$
现在,您可以将您关心的部分包装在捕获组中,为我们提供最终的正则表达式:
^,*((?:|\d+|"\d+,\d+"),(?:|\d+|"\d+,\d+"),(?:|\d+|"\d+,\d+")),*$
在正则表达式模式下搜索和替换,使用此正则表达式进行搜索,</code> 用于替换值。</p>
<p>如果多个字段为空,则可能有多种可能的解决方案。如果您的三个值中的第一个和最后一个值永远不会为空,您可以相应地调整正则表达式。如果是,这将选择 <em>one</em> 一组有效值,这可能不是您想要的。例如,如果您有:</p>
<pre><code>,,1,"2,3",,
那么 ,1,"2,3
(empty, 1, 2.3) 和 1,"2,3",
(1, 2.3, empty) 都是可能的解决方案。默认情况下,您将获得第二个结果,因为 *
是贪心的,即第一个 ,*
将尝试“吃掉”尽可能多的逗号而不会使匹配失败。您可以像这样添加一个问号:,*?
使匹配“懒惰”或“非贪婪”,然后它只会根据需要使用尽可能多的逗号(产生第一个结果)。