我希望用户输入一系列要打印的数字: 例如:
27-84
我想出了以下正则表达式:
^(?P<Begin>\d+)((-?)(?P<end>\d+)?)$
因此它将匹配:27-84
作为以下组:
Begin [0-2] `27`
2. [2-5] `-84`
3. [2-3] `-`
end [3-5] `84`
看起来不错,但我想听听是否有更优雅的方法,或者是否有我正在监督的空腔。
说明:
- 允许使用单个数字,例如:
27
。 - 单个数字以
27-
,应理解为27 to end
。 -10
的单个数字,应理解为begin to 10
。- 具有
10-27
的序列应理解为 10 到 27(含)。
最佳答案
(下面是原始答案)
好的,随着你的澄清更新,你将无法使用正则表达式轻松地做到这一点那个,除非你也只接受一个-
作为“从头开始结束”。在这种情况下,你可以使用这个:
>>> r = re.compile('^((?P<fixed>\d+)|(?P<begin>\d+)?-(?P<end>\d+)?)$')
>>> r.match('123').groupdict()
{'begin': None, 'fixed': '123', 'end': None}
>>> r.match('123-').groupdict()
{'begin': '123', 'fixed': None, 'end': None}
>>> r.match('-456').groupdict()
{'begin': None, 'fixed': None, 'end': '456'}
>>> r.match('-').groupdict()
{'begin': None, 'fixed': None, 'end': None}
>>> r.match('123-456').groupdict()
{'begin': '123', 'fixed': None, 'end': '456'}
否则,您将不得不使用更明确的案例:
>>> r = re.compile('^((?P<fixed>\d+)|-(?P<endonly>\d+)|(?P<begin>\d+)(?:-(?P<end>\d+)?))$')
>>> r.match('123').groupdict()
{'endonly': None, 'begin': None, 'fixed': '123', 'end': None}
>>> r.match('123-').groupdict()
{'endonly': None, 'begin': '123', 'fixed': None, 'end': None}
>>> r.match('-456').groupdict()
{'endonly': '456', 'begin': None, 'fixed': None, 'end': None}
>>> r.match('123-456').groupdict()
{'endonly': None, 'begin': '123', 'fixed': None, 'end': '456'}
>>> r.match('-') is None
True
如您所见,随后正确解释结果所需的工作量会增加。
不过,我建议您为此放弃正则表达式,直接在 Python 中进行解析。例如像这样:
def parseRange (expr):
if not expr or not re.match('^\d*-?\d*$', expr):
raise ValueError('Not a correct range')
# single number
if '-' not in expr:
return int(expr), int(expr)
else:
begin, end = expr.split('-')
begin = float('-inf') if begin == '' else int(begin)
end = float('inf') if end == '' else int(end)
return begin, end
这样使用:
>>> parseRange('123')
(123, 123)
>>> parseRange('123-')
(123, inf)
>>> parseRange('-456')
(-inf, 456)
>>> parseRange('123-456')
(123, 456)
原始答案
你可以去掉一些捕获组来简化它:
^(?P<begin>\d+)-(?P<end>\d+)$
这也解决了 -
可能没有第二个数字的问题,并且理论上(实际上)开始和结束可以没有任何分隔。
如果你不总是想匹配一个范围但又想允许单个数字,你可以将范围部分放在非捕获组中。这样你就不会得到额外的组:
^(?P<begin>\d+)(?:-(?P<end>\d+))?$
最后,如果你也想接受 to
作为分隔符,你甚至可以这样做:
^(?P<begin>\d+)(?:(?:-|\s+to\s+)(?P<end>\d+))?$
>>> r = re.compile('^(?P<begin>\d+)(?:-(?P<end>\d+))?$')
>>> r.match('123').groupdict()
{'begin': '123', 'end': None}
>>> r.match('123-456').groupdict()
{'begin': '123', 'end': '456'}
>>> r = re.compile('^(?P<begin>\d+)(?:(?:-|\s+to\s+)(?P<end>\d+))?$')
>>> r.match('123-456').groupdict()
{'begin': '123', 'end': '456'}
>>> r.match('123 to 456').groupdict()
{'begin': '123', 'end': '456'}
关于Python 正则表达式 : match a range of numbers with a separator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21511831/