2017-08-15 4 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の他のではなく、1 またはと一致していることかもしれないと思います。 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のための正規表現エンジンの異なるバージョン内にある必要があります違いのための決定的な理由は、しかし、比類のないグループに関するre.sub()のバージョン3.5で文書化変化がある:

バージョン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

おかげで、これは両方のバージョンに適しています。 :) –