在正则表达式python中,有没有一种方法可以检查同一字符串中的两种不同模式?

在正则表达式python中,有没有一种方法可以检查同一字符串中的两种不同模式?,python,regex,Python,Regex,我想从字符串中提取某些数字。问题是字符串可以包含两种不同模式的数字。如何在re.search中创建正则表达式模式,以便在单个字符串中搜索两种模式 例如 ## extract 65.45 from this string string = '1112 (65.45%)' 所以,如果我做了下面的事情,它会起作用 re.search('.*?\((.*)%\)', string).group(1) 我得到了预期的结果65.45 现在,我需要查找同一文本中的另一种字符串 ## from this s

我想从字符串中提取某些数字。问题是字符串可以包含两种不同模式的数字。如何在
re.search
中创建正则表达式模式,以便在单个字符串中搜索两种模式

例如

## extract 65.45 from this string
string = '1112 (65.45%)'
所以,如果我做了下面的事情,它会起作用

re.search('.*?\((.*)%\)', string).group(1)
我得到了预期的结果
65.45

现在,我需要查找同一文本中的另一种字符串

## from this string, extract 4.00 which appears before [
string = '4.00 [3.00 - 4.50]'

re.search('^(\S+)\s\[.*', string).group(1)
给我想要的结果:4.00

但是如果我像下面这样组合它们,它只提取第一个匹配的

re.search('^(\S+)\s\[.*|.*?\((.*)%\)', string).group(1)
在这种情况下,只有包含方括号的字符串才能提取该值,如果该字符串有%符号则不会。我怎样才能解决这个问题

例如,如果我有如下字符串列表:

['73 (1.40%)', '38 (1.55%)', '27 (2.17%)', '32 (1.46%)', '10 (1.46%)', '11 (1.04%)', '11 (1.41%)', '7 (1.34%)', '4 (1.24%)', '28 (1.27%)', '750 (14.41%)', '381 (15.54%)', '182 (14.60%)', '313 (14.27%)', '4.10 [3.73 - 4.45]', '4.08 [3.70 - 4.42]', '4.13 [3.77 - 4.47]', '4.13 [3.78 - 4.47]', '4.07 [3.70 - 4.42]', '4.07 [3.70 - 4.43]', '4.07 [3.70 - 4.40]', '4.09 [3.73 - 4.42]', '4.03 [3.63 - 4.40]', '4.10 [3.70 - 4.47]']
<re.Match object; span=(0, 10), match='73 (1.40%)'>
<re.Match object; span=(0, 10), match='38 (1.55%)'>
<re.Match object; span=(0, 10), match='27 (2.17%)'>
<re.Match object; span=(0, 10), match='32 (1.46%)'>
<re.Match object; span=(0, 10), match='10 (1.46%)'>
<re.Match object; span=(0, 10), match='11 (1.04%)'>
<re.Match object; span=(0, 10), match='11 (1.41%)'>
<re.Match object; span=(0, 9), match='7 (1.34%)'>
<re.Match object; span=(0, 9), match='4 (1.24%)'>
<re.Match object; span=(0, 10), match='28 (1.27%)'>
<re.Match object; span=(0, 12), match='750 (14.41%)'>
<re.Match object; span=(0, 12), match='381 (15.54%)'>
<re.Match object; span=(0, 12), match='182 (14.60%)'>
<re.Match object; span=(0, 12), match='313 (14.27%)'>
<re.Match object; span=(0, 18), match='4.10 [3.73 - 4.45]'>
<re.Match object; span=(0, 18), match='4.08 [3.70 - 4.42]'>
<re.Match object; span=(0, 18), match='4.13 [3.77 - 4.47]'>
<re.Match object; span=(0, 18), match='4.13 [3.78 - 4.47]'>
<re.Match object; span=(0, 18), match='4.07 [3.70 - 4.42]'>
<re.Match object; span=(0, 18), match='4.07 [3.70 - 4.43]'>
<re.Match object; span=(0, 18), match='4.07 [3.70 - 4.40]'>
<re.Match object; span=(0, 18), match='4.09 [3.73 - 4.42]'>
<re.Match object; span=(0, 18), match='4.03 [3.63 - 4.40]'>
<re.Match object; span=(0, 18), match='4.10 [3.70 - 4.47]'>
我想对提取的每个值执行某些操作,并与特定阈值进行比较

使用for循环,我做了如下操作:

for val in string: 
    match = re.search('^(\S+)\s\[.*|.*?\((.*)%\)', val)
    print(match)
其结果如下:

['73 (1.40%)', '38 (1.55%)', '27 (2.17%)', '32 (1.46%)', '10 (1.46%)', '11 (1.04%)', '11 (1.41%)', '7 (1.34%)', '4 (1.24%)', '28 (1.27%)', '750 (14.41%)', '381 (15.54%)', '182 (14.60%)', '313 (14.27%)', '4.10 [3.73 - 4.45]', '4.08 [3.70 - 4.42]', '4.13 [3.77 - 4.47]', '4.13 [3.78 - 4.47]', '4.07 [3.70 - 4.42]', '4.07 [3.70 - 4.43]', '4.07 [3.70 - 4.40]', '4.09 [3.73 - 4.42]', '4.03 [3.63 - 4.40]', '4.10 [3.70 - 4.47]']
<re.Match object; span=(0, 10), match='73 (1.40%)'>
<re.Match object; span=(0, 10), match='38 (1.55%)'>
<re.Match object; span=(0, 10), match='27 (2.17%)'>
<re.Match object; span=(0, 10), match='32 (1.46%)'>
<re.Match object; span=(0, 10), match='10 (1.46%)'>
<re.Match object; span=(0, 10), match='11 (1.04%)'>
<re.Match object; span=(0, 10), match='11 (1.41%)'>
<re.Match object; span=(0, 9), match='7 (1.34%)'>
<re.Match object; span=(0, 9), match='4 (1.24%)'>
<re.Match object; span=(0, 10), match='28 (1.27%)'>
<re.Match object; span=(0, 12), match='750 (14.41%)'>
<re.Match object; span=(0, 12), match='381 (15.54%)'>
<re.Match object; span=(0, 12), match='182 (14.60%)'>
<re.Match object; span=(0, 12), match='313 (14.27%)'>
<re.Match object; span=(0, 18), match='4.10 [3.73 - 4.45]'>
<re.Match object; span=(0, 18), match='4.08 [3.70 - 4.42]'>
<re.Match object; span=(0, 18), match='4.13 [3.77 - 4.47]'>
<re.Match object; span=(0, 18), match='4.13 [3.78 - 4.47]'>
<re.Match object; span=(0, 18), match='4.07 [3.70 - 4.42]'>
<re.Match object; span=(0, 18), match='4.07 [3.70 - 4.43]'>
<re.Match object; span=(0, 18), match='4.07 [3.70 - 4.40]'>
<re.Match object; span=(0, 18), match='4.09 [3.73 - 4.42]'>
<re.Match object; span=(0, 18), match='4.03 [3.63 - 4.40]'>
<re.Match object; span=(0, 18), match='4.10 [3.70 - 4.47]'>

.group
返回捕获的组,因此
.group(1)
始终返回第一个捕获的组


要获取另一个捕获组,请使用
.group(2)

这里有一种方法,可用于精确输入,其中每个列表条目始终具有两种匹配模式之一:

[代码>是项项工程项目是在以下方面进行进行的:<代码>是项项工程项目是在以下以下方面而而而<<代码>是以下以下以下是是是<<<代码><<<代码>>是项项工程项目是在他们他们他们他们他们他们他们他们他们他们他们他们在他们他们他们他们担任担任‘73(1.40.40百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百百份份份份份份份份份份份份份份份份份份份份份份份份份份份份份份"4.07[3.70-4.42],"4.07[3.70-4.43]', '4.07 [3.70 - 4.40]', '4.09 [3.73 - 4.42]', '4.03 [3.63 - 4.40]', '4.10 [3.70 - 4.47]'] 匹配项=[re.findall(r'\b\d+\(\d+(?:\.\d+))\(\d+(?:\.\d+)?)\[\d+(?:\.\d+)-\d+(?:\.\d+)\,x)表示inp中的x] 匹配项=[x[0][0]+x[0][1]表示匹配项中的x] 打印(匹配) 这张照片是:

['1.40%', '1.55%', '2.17%', '1.46%', '1.46%', '1.04%', '1.41%', '1.34%',
 '1.24%', '1.27%', '14.41%', '15.54%', '14.60%', '14.27%', '4.10', '4.08',
 '4.13', '4.13', '4.07', '4.07', '4.07', '4.09', '4.03', '4.10']

上面使用的策略是在两个单独的组中匹配百分比输入中的第一个数字或方括号外的数字。然后,在列表理解中,我们将两个捕获组连接在一起。由于两个组中的一个保证为空,因此连接的结果总是与所需的匹配相对应。

我只需要使用一个简单正则表达式列表,并对每个要测试的字符串进行迭代。将使用第一个命中的正则表达式。我还将预先编译正则表达式以节省CPU周期。这在可读性方面更容易遵循,并且易于添加新模式:

import re

regexs = [
    re.compile(r".*?\((.*)%\)"), 
    re.compile(r"^(\S+)\s\[.*"),
]

data = [
    "73 (1.40%)",
    "38 (1.55%)",
    "27 (2.17%)",
    "750 (14.41%)",
    "381 (15.54%)",
    "4.10 [3.73 - 4.45]",
    "4.08 [3.70 - 4.42]",
    "4.13 [3.77 - 4.47]",
    "this shouldn't match"
]


for val in data:
    for regex in regexs:
        if match := regex.search(val):
            print("Matched: " + match.group(1))
            break
    else:
        print("No match: " + val)
产出:

Matched: 1.40
Matched: 1.55
Matched: 2.17
Matched: 14.41
Matched: 15.54
Matched: 4.10
Matched: 4.08
Matched: 4.13
No match: this shouldn't match

另一种选择是使用lookarounds仅获取匹配:

(?<=\()\d+(?:\.\d+)?(?=%\))|\d+(?:\.\d+)?(?=\s*\[[^][]*])
输出

<re.Match object; span=(4, 8), match='1.40'>
<re.Match object; span=(4, 8), match='1.55'>
<re.Match object; span=(4, 8), match='2.17'>
<re.Match object; span=(4, 8), match='1.46'>
<re.Match object; span=(4, 8), match='1.46'>
<re.Match object; span=(4, 8), match='1.04'>
<re.Match object; span=(4, 8), match='1.41'>
<re.Match object; span=(3, 7), match='1.34'>
<re.Match object; span=(3, 7), match='1.24'>
<re.Match object; span=(4, 8), match='1.27'>
<re.Match object; span=(5, 10), match='14.41'>
<re.Match object; span=(5, 10), match='15.54'>
<re.Match object; span=(5, 10), match='14.60'>
<re.Match object; span=(5, 10), match='14.27'>
<re.Match object; span=(0, 4), match='4.10'>
<re.Match object; span=(0, 4), match='4.08'>
<re.Match object; span=(0, 4), match='4.13'>
<re.Match object; span=(0, 4), match='4.13'>
<re.Match object; span=(0, 4), match='4.07'>
<re.Match object; span=(0, 4), match='4.07'>
<re.Match object; span=(0, 4), match='4.07'>
<re.Match object; span=(0, 4), match='4.09'>
<re.Match object; span=(0, 4), match='4.03'>
<re.Match object; span=(0, 4), match='4.10'>


但如果我在循环中执行此操作,如何确定要捕获哪个组。文本可以在任何运行时显示?我只是试图避免对
%
进行有条件搜索,或者如果我可以用一种方法进行搜索的话,也可以使用其他方法line@Kuni检查表达式中括号的位置。如果捕获组不捕获任何内容,则该组可以为空。能否包含一个样本输入,其中包含要匹配的内容的两个版本,以及捕获的值?@TimBiegeleisen,我刚刚添加了一个要检查的值列表。这就是你想要的吗?我真的很喜欢这个解决方案,因为它不需要我更改正则表达式,而且如果需要,我还可以在以后添加其他正则表达式。