2017-08-15 40 views
13

我正在写一个函数来从Python中的文本中拆分数字和其他一些东西。该代码看起来是这样的:Python 2和3're.sub'不一致

EN_EXTRACT_REGEX = '([a-zA-Z]+)' 
NUM_EXTRACT_REGEX = '([0-9]+)' 
AGGR_REGEX = EN_EXTRACT_REGEX + '|' + NUM_EXTRACT_REGEX 

entry = re.sub(AGGR_REGEX, r' \1\2', entry) 

现在,这个代码在python3完全正常,但它不会在python2工作,并得到一个“无与伦比组”的错误。

问题是,我需要支持这两个版本,我不能让它在python2中正常工作,尽管我尝试了各种其他方式。

我很好奇什么可能是这个问题的根源,是否有任何解决方法?

回答

10

我认为这个问题可能是正则表达式模式匹配的子模式EN_EXTRACT_REGEXNUM_EXTRACT_REGEX,但不能同时的一个其他。

re.sub()与第一个模式中的字母字符相匹配时,它将尝试替换第二个组参考\2,因为只有第一个组匹配 - 第二个组没有匹配。

类似地,当数字模式匹配时,没有\1组进行替换,所以这也失败了。

你可以看到,这是与该测试在Python 2的情况下:

>>> re.sub(AGGR_REGEX, r' \1', 'abcd') # reference first pattern 
abcd 
>>> re.sub(AGGR_REGEX, r' \2', 'abcd') # reference second pattern 
Traceback (most recent call last): 
.... 
sre_constants.error: unmatched group 

的区别在于必须为Python 2和Python 3的不同版本的正则表达式引擎的内部可惜我不能提供一个明确的理由不同,但是,有在3.5版本中关于无法比拟的一组记录变化为re.sub()

改变在3.5版本:无与伦比组与空字符串替换。

它解释了为什么它在Python> = 3.5中工作,但不在早期版本中:基本忽略不匹配的组。


作为一种变通方法,你可以改变你的模式来处理两场比赛作为一个组:

import re 

EN_EXTRACT_REGEX = '[a-zA-Z]+' 
NUM_EXTRACT_REGEX = '[0-9]+' 
AGGR_REGEX = '(' + EN_EXTRACT_REGEX + '|' + NUM_EXTRACT_REGEX + ')' 
# ([a-zA-Z]+|[0-9]+) 

for s in '', '1234', 'abcd', 'a1b2c3', 'aa__bb__1122cdef', '_**_': 
    print(re.sub(AGGR_REGEX, r' \1', s)) 

输出

 

1234 
abcd 
a 1 b 2 c 3 
aa__ bb__ 1122 cdef 
_**_ 
+0

谢谢,这个效果很好的两个版本。 :) –