【问题标题】:REGEX for overlapped/intermingled rows用于重叠/混合行的 REGEX
【发布时间】:2021-08-26 12:53:22
【问题描述】:

我遇到了一个非常烦人的问题,这是由于不可靠的 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

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

帮助表示赞赏!

【问题讨论】:

    标签: regex multiple-columns rows overlapping-matches


    【解决方案1】:

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

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

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

    查看regex demo

    使用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')]
    

    【讨论】:

    • 非常感谢您的回复 - 这看起来可能是下坡路。唯一的问题是,我不知道有多少行,可能是 1 行,也可能是 20 行。有没有一种简单的方法可以更改代码来解决这个问题?我尝试了这个可怕的事情,但我还没有完全明白: ([AZ]+)(?=(?:\s+\S+)+(\S+)(?:\s+\S+)+(\S+))
    • @GarethWard 你说的行是什么意思?你的意思是现在你有 3 个,可能有 20 个部分。在这种情况下,您可以使用量词 ([A-Z]+)(?=(?:\s+\S+){3}\s*(\d+(?:\.\d+)?)(?:\s+\S+){3}\s+(\d+)) regex101.com/r/ArU5GE/1 请注意,此方法仅在列值为单个“单词”时才有效
    • 再次感谢我对此感到兴奋!行,我的意思是在原始模式中,有3个“组”重叠,即3行,[('ABC','45.00','4'),('FED','60.00','5 '), ('GHK', '30.00', '5')]。可能只有一个,也可能只有 20 个,例如:[('ABC', '45.00', '4'), ('FED', '60.00', '5'), ('GHK', '30.00 ', '5'), ('GHK', '30.00', '5'), ('GHK', '30.00', '5'), ('GHK', '30.00', '5'), ( 'GHK', '30.00', '5'), ('GHK', '30.00', '5'), ('GHK', '30.00', '5'), ('GHK', '30.00', '5')] 所以 5 'rows' 看起来像 abc abc abc abc abc 40.00 40.00 40.00 40.00 40.00 4 5 6 5 6,如果你知道的话!
    • @GarethWard 是这样的([A-Za-z]+)(?=(?:\s+\S+){4}\s*(\d+(?:\.\d+)?)(?:\s+\S+){4}\s+(\d+))regex101.com/r/9Cn9T6/1
    • 所以如果我知道在执行 REGEX 之前有多少行,我可以看到如何更改它(这应该很容易解决,所以这应该让我到达我想去的地方希望!)。我猜想在不知道会有多少行的情况下让它工作会是一个太大的问题,即一个单一的正则表达式模式同时适用于包含 3 行、4 行、5 行等的字符串。例如,如果我输入一个 {1,},那只会破坏它,因为它匹配了尽可能多的次数。感谢您的意见!
    猜你喜欢
    • 2015-05-20
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多