2

我遇到了这个由不可靠的 PDF 数字化引起的非常恼人的问题。

无论如何,理想情况下,一系列具有不同列的行将表示如下:

Code  Cost  Quantity
ABC  45.00  4
FED  60.00  5
GHK  30.00  5

使用正则表达式很容易将它们拆分为行,然后获取每个单独的列。

但是,我发现一个特别烦人的文本总是这样出现:

Code  Cost  Quantity
ABC FED GHK   45.00 60.00 30.00  4 5 5

我一生都无法弄清楚如何让正则表达式分离出每个重叠的行,就像第一个例子一样。积极的前瞻可以让我得到一些帮助,但通常会发生 ABC 45.00 4 然后是 FED 45.00 4,我建立的前瞻不会遍历所有单独的列。

我的怀疑是我可以使用命名模式或其他东西,匹配第一组:

(?>(?<match1>((?>\s|\b)\w{3}\s).+\s+\s(\d+\.\d{2})\s.*\s+\s(\d{1})\s.*))

然后以某种方式重用该捕获组,对其进行迭代。

向前看只会迭代第一组,所以我显然在做一些愚蠢的事情:

https://regex101.com/r/Uxx8bZ/1

从理论上讲,我可以通过其他方式将行分开(例如,对于每个大空间,这是一列),但似乎这应该是可能的。

帮助表示赞赏!

4

1 回答 1

1

在示例数据中,随附的数据是 3 次空白字符,然后是右侧的非空白字符。

如果该结构始终相同,您可以捕获大写字符,并捕获前瞻断言中的其他 2 个字段。

([A-Z]+)(?=\s+\S+\s+\S+\s+(\d+(?:\.\d+)?)\s+\S+\s+\S+\s+(\d+))
  • ([A-Z]+)在第 1 组中捕获 1+ 次 char AZ
  • (?=正向前瞻,向右断言
    • \s+\S+\s+\S+\s+(\d+(?:\.\d+)?)在 3 个字段之后,在第 2 组中捕获 1+ 个数字,其中包含可选的小数部分
    • \s+\S+\s+\S+\s+(\d+)在 3 个字段之后,捕获第 3 组中的 1+ 个数字
  • )关闭前瞻

查看正则表达式演示

使用re.findall 检索捕获组值的示例:

import re

pattern = r"([A-Z]+)(?=\s+\S+\s+\S+\s+(\d+(?:\.\d+)?)\s+\S+\s+\S+\s+(\d+))"
s = r"ABC FED GHK   45.00 60.00 30.00  4 5 5"
print(re.findall(pattern, s))

输出

[('ABC', '45.00', '4'), ('FED', '60.00', '5'), ('GHK', '30.00', '5')]
于 2021-06-09T15:33:45.787 回答