具有多层条件的Python正则表达式匹配组

标签 python regex python-3.x

我有这个正则表达式:

cont_we_re = r"((?!\S+\s?(?:(cbf|cd3|cbm|m3|m[\\\>\?et]?|f3|ft3)))(?:([0-9,\.]+){2,})(?:\s*(?:(lb|kg)\.?s?))?)"

现在,如果后跟 kgslbs,则后面的逻辑可选地与任何数字 block 匹配,但如果 cbf,则不匹配>, cd3, cbm, m3 等在数字 block 之后。它非常适合这些示例案例:

s1 = "18300 kg 40344.6 lbs 25000 m3"
s2 = "18300kg 40344.6lbs 25000m3"
s3 = "18300 kg   KO"
s4 = "40344.6 lb5   "
s5 = "40344.6  "

我正在使用带有 re.IGNORECASE 标志的 re.finditer(),像这样:

for s in [s1, s2, s3, s4, s5]:
    all_val = [i.group().strip() for i in re.finditer(cont_we_re, s, re.IGNORECASE)]

给我这个输出:

['18300 kg', '40344.6 lbs']
['18300kg', '40344.6lbs']
['18300 kg']
['40344.6 lb']
['40344.6']

现在我正在尝试实现另一个逻辑:如果我们找到后跟 lbs 的数字 block ,则将其与第一优先级匹配并仅返回该匹配项,但如果找不到 lbs 并只找到数字 block 或数字 block 后跟 kgs 然后取那些。

我在不更改正则表达式的情况下完成了此操作,如下所示:

for s in [s1, s2, s3, s4, s5]:
    all_val = [i.group().strip() for i in re.finditer(cont_we_re, s, re.IGNORECASE)]
    kg_val = [i for i in all_val if re.findall(r"kg\.?s?", i)]
    lb_val = [i for i in all_val if re.findall(r"lb\.?s?", i)]
    final_val = lb_val if lb_val else (kg_val if kg_val else list(set(all_val) - (set(kg_val+lb_val))))

这给了我想要的输出(这是完美的):

['40344.6 lbs']
['40344.6lbs']
['18300 kg']
['40344.6 lb']
['40344.6']

问题是我如何在正则表达式中应用相同的逻辑,而不通过 cont_we_re 在每个匹配组上分别找到 kgslbs对于每个字符串。我尝试了此 question 中描述的“IF-THEN-ELSE”类型正则表达式但它不能作为正则表达式的第一部分 (? 据说会在 python 中产生模式错误。有没有办法只用 cont_we_re 正则表达式来做到这一点?

最佳答案

使用 PyPi module 的可能解决方案可能正在利用 (*SKIP)(*FAIL)和环顾四周以检查是否存在 lb

(?:\d+(?:\.\d+)? ?lbs?|(?<!lb.*)(?!.*lb)\d+(?:\.\d+)?(?: kg)?|\d+(?:\.\d+)? ?kg(*SKIP)(*FAIL))
  • (?:非捕获组
    • \d+(?:\.\d+)? ?lbs?将数字格式与可选的小数部分匹配,后跟 lb 和可选的 s
    • |或者
    • (?<!lb.*)(?!.*lb)\d+(?:\.\d+)?(?: kg)?断言字符串不包含 lb , 然后将数字格式与可选的小数部分匹配,后跟 kg
    • |或者
    • \d+(?:\.\d+)? ?kg(*SKIP)(*FAIL)匹配数字格式后接 kg并跳过那场比赛
  • )关闭非捕获组

例如

import regex

s1 = "18300 kg 40344.6 lbs 25000 m3"
s2 = "18300kg 40344.6lbs 25000m3"
s3 = "18300 kg   KO"
s4 = "40344.6 lb5   "
s5 = "40344.6  "

cont_we_re = r"(?:\d+(?:\.\d+)? ?lbs?|(?<!lb.*)(?!.*lb)\d+(?:\.\d+)?(?: kg)?|\d+(?:\.\d+)? ?kg(*SKIP)(*FAIL))"


for s in [s1, s2, s3, s4, s5]:
    all_val = [i.group().strip() for i in regex.finditer(cont_we_re, s, regex.IGNORECASE)]
    print(all_val)

输出

['40344.6 lbs']
['40344.6lbs']
['18300 kg']
['40344.6 lb']
['40344.6']

Python demo

关于具有多层条件的Python正则表达式匹配组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59247464/

相关文章:

python - 如何在 Django 1.11 中查找给定月份的每周记录数?

python - Django - 将用户相关信息传递到许多 View

返回缩进字符串的 Python 三引号

regex - 在 Notepad++ 中从逗号或点字符后的文本字符串中获取特定子字符串

python 3 : Searching A Large Text File With REGEX

Python 无法从文件创建变量

python - 如何通过 ctypes 将列表列表从 Python 传递(非空)到 C++?

regex - 在 MongoDB 集合中查找正则表达式数组的匹配项

c++ - 在 C++ 程序中使用 for 循环的问题负责查找 XML 文件中包含 25 个数值的 6 行中每一行的平均值

linux - 如何使用python检测linux和windows后台的按键组合?