Skip to main content
 首页 » 编程设计

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

2024年09月03日26me-sa

我有这个正则表达式:

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

现在,如果后跟 kgs 或 lbs,则后面的逻辑可选地与任何数字 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 在每个匹配组上分别找到 kgs 和 lbs对于每个字符串。我尝试了此 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