2012-12-13 16 views
10

私はユニコード文字列に無効なXML 1.0文字を検出する正規表現しています。Linux/python2.7でなぜPythonの正規表現はLinuxではコンパイルされますが、Windowsではコンパイルされませんか?

bad_xml_chars = re.compile(u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]', re.U) 

を、これは完璧に動作します。ウィンドウズでは以下のように表示されます:

File "C:\Python27\lib\re.py", line 190, in compile 
    return _compile(pattern, flags) 
    File "C:\Python27\lib\re.py", line 242, in _compile 
    raise error, v # invalid expression 
    sre_constants.error: bad character range 

これはWindowsでコンパイルされない理由はありますか?

+1

Linux(Python 2.7も同じ)で同じエラーが発生します。 – interjay

+0

Linux、Python 2.7で動作します –

答えて

16

Windows上にnarrow Python buildがあるため、UnicodeはUTF-16を使用します。つまり、\uFFFFより大きいUnicode文字は、Python文字列の2つの別個の文字になります。あなたはこのようなものが表示されるはずです。ここで

>>> len(u'\U00010000') 
2 
>>> u'\U00010000'[0] 
u'\ud800' 
>>> u'\U00010000'[1] 
u'\udc00' 

を正規表現エンジンが狭い上、あなたの文字列を解釈しようとする方法です構築します

[^\x09\x0A\x0D\u0020-\ud7ff\ue000-\ufffd\ud800\udc00-\udbff\udfff] 

無効な範囲のメッセージがどこにある\udc00-\udbffがあることをここで見ることができますから来る。

+0

これはPython 3.3で修正する必要があります。すべてのビルドはワイドビルドのように動作します(少ないメモリ使用を除く)。 OPが3.3を使用することは実現できないかもしれないことを感謝します。 –

7

Windows版のPythonでは、16ビットを使用してUTF-16としてエンコードされたUnicode文字を表すため、動作しません。コードポイント10000以上はUTF-16で2つのコード単位として表され、-のいずれかの側に1文字が必要な範囲の表現reを混乱させます。文字が[...]を設定する内部

u'\ud800', u'\udc00', u'-', u'\udbff', u'\udfff' 

re.compile\U00010000-\U0010FFFFは5つの文字で表現される

>>> [x for x in u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]'] 
[u'[', u'^', u'\t', u'\n', u'\r', u' ', u'-', u'\ud7ff', u'\ue000', u'-', 
u'\ufffd', u'\ud800', u'\udc00', u'-', u'\udbff', u'\udfff', u']'] 

注こと:

これは、あなたがre.compileに渡している文字列を文字に分割する方法でありますこれを文字u'\ud800'u'\udfff'と解釈し、範囲はu'\udc00' - u'\udbff'と解釈します。この範囲は、その終了が開始よりも小さいため無効です。これにより、エラーが発生します。

1

悪い文字範囲を扱う標準ライブラリのセクション(Lib/sre_compile.py:450)があります:それはあなたの\U00010000-\U0010FFFF文字範囲のlohiリテラルを比較したとき、彼らは序56320であることに

if code1[0] != LITERAL or code2[0] != LITERAL: 
    raise error, "bad character range" 
lo = code1[1] 
hi = code2[1] 
if hi < lo: 
    raise error, "bad character range" 

出てくると56319(範囲が後方にあるため、もちろん失敗します)。

これは、Pythonが8文字のUnicodeリテラルを2つの別個の文字として扱うためです。

関連する問題