正则表达式代码太长且效率低下我想让它变得更好

问题描述

编辑:好的,我很抱歉,因为我对问题的第一个措辞过于简单,技术上正确的答案不适用于我的案例,所以这次我会尽量详细。

我正在构建一个正则表达式来捕获单个或复合代码。 每个代码都以“H”、“G”、“EUH”或“AUG”开头,后跟三位数字 (H123) 或三位数字、一个点和一位数字。 (H123.1)。 第一位不能是零。

每个 H 代码后可以跟一个或多个以下字符:“idDfF”.(H231Df)。 每个 P 代码后面可以跟一个或多个这些字符:“AEBDab”。(P333a)。 每个 EUH 代码后面都可以跟“A”。(EUH123A)。

化合物示例:H123Df+H234+H234.1+H342.1Fd 和 P123.1+P555D 空格可以在字符串中的任何地方,除了 3 位数字,这些数字总是相互跟随,没有空格。 点或破折号可以在末尾的额外字符之前(H123-Df,H123.Df)

我需要匹配每个复合或单个代码。请注意,在我之前的尝试中,我检测到 H567+H890+H654 正确,但也检测到 H567、H890 和 H654,这是错误的。一旦匹配了一个集合,它的内部代码不应再被视为单个代码

我目前的方法实际上是 4 种不同的正则表达式代码,每组代码一个。它主要有效(我猜),但它非常乏味,如果将另一个代码添加到化合物中将无法工作,并且在正则表达式中添加更复杂的东西时,它非常难以维护。 这是 P 代码的正则表达式示例。

`p = "P\s*\d{3}[.\s-]*[AEBDab]*\s*[+/]\s*P*\s*\d{3}[.\s-]*[AEBDab]*\s*[+/]\s*P*\s*\d{3}[.\s-]*[AEBDab]*|P\s*\d{3}[.\s-]*[AEBDab]*\s*[+/]\s*P*\s*\d{3}[.\s-][AEBDab]*|P\s*\d{3}[.\s-]*[AEBDab]*\s`"

如您所见,它非常长且效率低下,编辑一个小东西会花费很多时间并且很容易出错。

我怎样才能以更好的方式实现这一目标?是制作 4 个正则表达式更好还是仅使用一个来捕获所有 4 个代码的所有格式?

编辑: 一个真实的版本看起来就像这样:

text = "random text
H326random text H243Df+H546+H677-Drandom text
randomtext P234a+P333.Ddrandom text
someother randomtexts"

output = [H326,H243+H546+H677,H234+H333]

注意:所提供的文本中的空格非常随机,因为它们是用 pdfminer 库解析的 PDF 文本,它非常混乱的顺序和空格,但它是我发现的唯一一个实际上可以“读取”所有 10k 的库我有 PDF 文件,其他库会产生空字符串,或者只是读取 PDF 的一部分。

注意:如果你能解释一下你的答案,因为我在工作时总是在发现新的格式,我希望能够根据需要编辑正则表达式。

谢谢!

解决方法

这样的事情可能对你有用:

import re

i = 'random text H326 H243+H546+H677 H234+H333 some other random texts X567+X890+X654'
capture_letters = 'HPGX'
regex = rf'[{capture_letters}]\denter image description here(?:\+[{capture_letters}]\dgithub-comment)*'

print([i.group(0) for i in re.finditer(regex,i)])

将任何有效的字母作为 capture_letters 字符串中的代码开头。

如果有大写字母,您也可以使用 A-Z

,

根据您展示的样品,您可以尝试以下操作吗?

import re
value = 'X123 X234+X567 some intermixed text X567+X890+X654 some extra text'
regex = r'(([a-zA-Z]+\d{3}\+?){1,})'
print([key.group(0) for key in re.finditer(regex,value)])

输出如下:

['X123','X234+X567','X567+X890+X654']
,

因此,根据您的评论,您似乎可以将 re.findall 与以下模式一起使用:

\b[HPGX]\d{3}(?:\+[HPGX]\d{3})*\b

查看在线demo

  • \b - 词边界。
  • [HPGX] - 提到的字符类中的单个字符。
  • \d{3} - 三位数。
  • (?: - 打开非捕获组:
    • \+ - 文字“+”。
    • [HPGX] - 提到的字符类中的单个字符。
    • \d{3} - 三位数。
    • )* - 关闭非捕获组并匹配 0 次以上(贪婪)。
  • \b - 词边界。

import re
txt = 'random text H326 H243+H546+H677 H234+H333 some other random texts'
lst = re.findall(r'\b[HPGX]\d{3}(?:\+[HPGX]\d{3})*\b',txt)
print(lst)

打印:

['H326','H243+H546+H677','H234+H333']
,

您可以使用 recursive regex 简化带有 regex 的正则表达式 (不是 re)模块。

import regex

text = """random text
H326random text H243Df+H546+H677-Drandom text
randomtext P234a+P333.Ddrandom text
someother randomtexts"""

m = regex.finditer(r'(H\s*\d{3}[.\s-]*[idDfF]*|(?:AU)?G\s*\d{3}(?:\.\d)|P\s*\d{3}[.\s-]*[AEBDab]*|EUH\s*\d{3}\s*A?)(?:\+(?1))*',text)
print([i.group(0) for i in m])

结果:

['H326','H243Df+H546+H677-D','P234a+P333.D']

说明:

  • 正则表达式 (H\s*\d{3}[.\s-]*[idDfF]*|(?:AU)?G\s*\d{3}(?:\.\d)|P\s*\d{3}[.\s-]*[AEBDab]*|EUH\s*\d{3}\s*A?) 是代码的规范。如果我不是 完全理解规则后,您将很容易修复正则表达式。 该模式用括号括起来,并在以下模式中作为 (?1) 重新使用。
  • 正则表达式 (?:\+(?1))* 是一个加号和 (?1) 的簇, 上面定义的递归正则表达式。
  • 匹配的子字符串被称为 group(0)