我有以下正则表达式,用于在字符串中查找数字
-?\d*\.?\d+([eE][-+]?\d+)?
并希望对其进行修改,使其仅匹配浮点数而不匹配整数。对此的标准(据我所知)是匹配必须至少具有以下特征之一:.
, e
, E
。但是,我想不出一种在不复制大部分正文的情况下将此要求合并到正则表达式中的好方法。
复制
经过一番搜索,我遇到了正则表达式匹配浮点数,但不是整数,虽然标题不明确,但与这个问题完全一致(包括 soln)。
我有以下正则表达式,用于在字符串中查找数字
-?\d*\.?\d+([eE][-+]?\d+)?
并希望对其进行修改,使其仅匹配浮点数而不匹配整数。对此的标准(据我所知)是匹配必须至少具有以下特征之一:.
, e
, E
。但是,我想不出一种在不复制大部分正文的情况下将此要求合并到正则表达式中的好方法。
复制
经过一番搜索,我遇到了正则表达式匹配浮点数,但不是整数,虽然标题不明确,但与这个问题完全一致(包括 soln)。
以下正则表达式执行此操作,尽管它有点神秘:
-?(?:\d+())?(?:\.\d*())?(?:e-?\d+())?(?:\2|\1\3)
解释:
一个数由三个部分组成(整数部分、小数部分和指数部分)。如果存在小数部分,则为 a float
,但如果不存在,则当指数部分跟随时,该数字仍然可以是浮点数。
这意味着我们首先必须在正则表达式中使所有三个部分都是可选的。但是随后我们需要建立规则来准确指定哪些部分需要在那里才能产生有效的浮动。
幸运的是,有一个技巧可以让我们做到这一点。空捕获组 ( ()
) 始终匹配(空字符串)。\1
仅当该组已参与比赛时,对该组 ( ) 的反向引用才会成功。通过在每个可选组中插入一个()
,我们可以稍后测试所需的部分是否参与了比赛。
例如,在 Python 中:
regex = re.compile(r"""
-? # Optional minus sign
(?: # Start of the first non-capturing group:
\d+ # Match a number (integer part)
() # Match the empty string, capture in group 1
)? # Make the first non-capturing group optional
(?: # Start of the second non-capturing group:
\.\d* # Match a dot and an optional fractional part
() # Match the empty string, capture in group 2
)? # Make the second non-capturing group optional
(?: # Start of the third non-capturing group:
e # Match an e or E
-? # Match an optional minus sign
\d+ # Match a mandatory exponent
() # Match the empty string, capture in group 3
)? # Make the third non-capturing group optional
(?: # Now make sure that at least the following groups participated:
\2 # Either group 2 (containing the empty string)
| # or
\1\3 # Groups 1 and 3 (because "1" or "e1" alone aren't valid matches)
)""", re.I|re.X)
测试套件:
>>> [match.group(0) for match in
... regex.finditer("1 1.1 .1 1. 1e1 1.04E-1 -.1 -1. e1 .1e1")]
['1.1', '.1', '1.', '1e1', '1.04E-1', '-.1', '-1.', '.1e1']
我想我会去
(-?\d*\.\d+([eE][-+]?\d+)?) | (-?\d+[eE][-+]?\d+)
第一部分与您的原始表达式相同,但需要句点。第二个捕获没有句点的情况,需要[eE][-+]?\d+
部分。
这是我的解决方案,使用前瞻来允许'1e1'
,但不是其他没有小数点的值:
>>> pattern = r'[+-]?(?:\d+\.\d*|\.\d+|\d+(?=[eE]))(?:[eE][+-]?\d+)?'
>>> re.match(pattern, '4.')
<_sre.SRE_Match object at 0x000000000347BD30>
>>> re.match(pattern, '4.4')
<_sre.SRE_Match object at 0x000000000347BCC8>
>>> re.match(pattern, '.4')
<_sre.SRE_Match object at 0x000000000347BD30>
>>> re.match(pattern, '4e4')
<_sre.SRE_Match object at 0x000000000347BCC8>