我有以下数据:
$200 – $4,500
Points – $2,500
我想捕获美元的范围,或者捕获Points
字符串(如果这是较低的范围(。
例如,如果我在上面的每个条目上运行regex,我会期望:
Group 1: 200
Group 2: 4,500
和
Group 1: Points
Group 2: 2,500
对于第一组,我不知道如何在允许捕获Points
的情况下只捕获整数值(没有$
符号(。
以下是我尝试过的:
(?:$([0-9,]+)|Points) – $([0-9,]+)
https://regex101.com/r/mD9JeR/1
只需在此处使用一个替换:
^(?:(Points)|$(d{1,3}(?:,d{3})*)) - $(d{1,3}(?:,d{3})*)$
演示
上述正则表达式模式的要点是,我们使用交替来匹配范围下端的Points
或美元金额,并且我们使用以下正则表达式来匹配带逗号的美元金额:
$d{1,3}(?:,d{3})*
生成一个与$
不匹配的正则表达式并不困难。得出一个与$
不匹配的正则表达式,并一致地放置这两个值,无论它们都是数字还是其中一个是Points
,因为捕获组1和2并不简单。如果使用命名的捕获组,困难就会消失。此正则表达式需要PyPi存储库中的regex
模块,因为它多次使用相同的命名组。
import regex
tests = [
'$200 – $4,500',
'Points – $2,500'
]
re = r"""(?x) # verbose mode
^ # start of string
(
$ # first alternate choice
(?P<G1>[d,]+) # named group G1
| # or
(?P<G1>Points) # second alternate choice
)
x20–x20 # ' – '
$
(?P<G2>[d,]+) # named group g2
$ # end of string
"""
# or re = r'^($(?P<G1>[d,]+)|(?P<G1>Points)) – $(?P<G2>[d,]+)$'
for test in tests:
m = regex.match(re, test)
print(m.group('G1'), m.group('G2'))
打印:
200 4,500
Points 2,500
更新
@marianc的评论是正确的,但没有确保输入中没有多余的字符。因此,有了他有用的投入:
import re
tests = [
'$200 – $4,500',
'Points – $2,500',
'xPoints – $2,500',
]
rex = r'((?<=^$)d{1,3}(?:,d{3})*|(?<=^)Points) – $(d{1,3}(?:,d{3})*)$'
for test in tests:
m = re.search(rex, test)
if m:
print(test, '->', m.groups())
else:
print(test, '->', 'No match')
打印:
$200 – $4,500 -> ('200', '4,500')
Points – $2,500 -> ('Points', '2,500')
xPoints – $2,500 -> No match
请注意,由于在行的开头执行的后备断言不可能成功,因此会执行search
而不是match
。但是,通过在我们的后备断言中包含^
锚,我们在行的开头不强制使用无关字符。
对于第一个捕获组,您可以使用与Points匹配的交替,并断言左侧是非空白字符,或者使用可选的十进制值来匹配数字,断言左侧是美元符号(如果支持的话(。
对于第二个捕获组,没有其他选择,因此您可以匹配美元符号,并在组2中捕获具有可选十进制值的数字。
((?<=$)d{1,3}(?:,d{3})*|(?<!S)Points) – $(d{1,3}(?:,d{3})*)
解释
(
捕获组1(?<=$)d{1,3}(?:,d{3})*
正向查找,向左断言一个$
并匹配1-3位数字,并重复0+匹配逗号和3位数字|
或(?<!S)Points
正向查找,在左侧断言一个非空白字符并匹配点
)
关闭组1–
按字面匹配$
匹配$
(
捕获组2d{1,3}(?:,d{3})*
匹配1-3位数字和0+倍逗号和3位数字
)
关闭组
Regex演示