2009-11-10 4 views
23

XML specification은 불법이거나 "낙담"한 유니 코드 문자를 나열합니다. 문자열이 있으면 어떻게 불법 문자를 모두 제거 할 수 있습니까?파이썬에서 불법 xml 유니 코드 문자를 빠르게 필터링하는 방법은 무엇입니까?

나는 다음 정규 표현식을 생각해 냈지만 약간의 입에 불과합니다.

illegal_xml_re = re.compile(u'[\x00-\x08\x0b-\x1f\x7f-\x84\x86-\x9f\ud800-\udfff\ufdd0-\ufddf\ufffe-\uffff]') 
clean = illegal_xml_re.sub('', dirty) 

는 (파이썬 2.5은 0xFFFF가 위의 유니 코드 문자에 대해 사람들을 필터링 할 수 있으므로 필요를 알고하지 않습니다.) 또한 선택된 코드 포인트를 삭제의이 방법을 번역 유니 코드를 사용할 수

+0

파이썬의 최대 유니 코드 코드 포인트는 컴파일시 어떻게 구성되었는지에 따라 달라지며'sys.maxunicode'를 확인하십시오. – u0b34a0f6ae

+0

당신 말이 맞아요. 나는 그것이 훨씬 더 복잡하다고 생각한다. – itsadok

+2

내 컴퓨터에서이 정규 표현식을 사용하여 2.3MB 문자열을 처리하는 데 0.34 초가 소요됩니다. 그것은 나에게 꽤 빠를 것 같다. –

답변

11

최근에 우리 (Trac의 XmlRpcPlugin 테이너가) 사실을 통보 한을 그 정규 표현식 위의 코드는 파이썬의 좁은 빌드에서 서로 게이트 쌍을 제거합니다 (th:comment:13:ticket:11050 참조). 다른 접근법은 다음 정규식을 사용하는 것입니다 (th:changeset:13729 참조).

_illegal_unichrs = [(0x00, 0x08), (0x0B, 0x0C), (0x0E, 0x1F), 
         (0x7F, 0x84), (0x86, 0x9F), 
         (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF)] 
if sys.maxunicode >= 0x10000: # not narrow build 
     _illegal_unichrs.extend([(0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), 
           (0x3FFFE, 0x3FFFF), (0x4FFFE, 0x4FFFF), 
           (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF), 
           (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), 
           (0x9FFFE, 0x9FFFF), (0xAFFFE, 0xAFFFF), 
           (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF), 
           (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), 
           (0xFFFFE, 0xFFFFF), (0x10FFFE, 0x10FFFF)]) 

_illegal_ranges = ["%s-%s" % (unichr(low), unichr(high)) 
        for (low, high) in _illegal_unichrs] 
_illegal_xml_chars_RE = re.compile(u'[%s]' % u''.join(_illegal_ranges)) 

p.s. 해당 내용을 설명하는 this post on surrogates을 참조하십시오.

업데이트0x0D과 일치하지 않으므로 (바꾸기) valid XML character입니다.

+0

대리자 쌍은 W3C XML 사양의 합법적 인 문자에서 명시 적으로 제외되므로 모든 XML이 다른 라이브러리에서 올바르게 구문 분석되지 않을 수 있습니다. 그러나 일반적으로 XML을 utf-8 또는 utf-16으로 직렬화하므로 문제가 사라집니다. utf-32에서 벗어나십시오. – itsadok

+0

0x0D 문자와 일치하도록 정규식을 업데이트했습니다. [th : ticket : 11635] (http://trac-hacks.org/ticket/11635), [th : changeset : 13776] (http://trac-hacks.org/changeset/13776) 및 [XML 문자 범위 정의] (http://www.w3.org/TR/REC-xml/#NT-Char)를 참조하십시오. –

+0

좋은 지적. 내 버전도 업데이트했습니다. – itsadok

3

. 그러나, 당신이 가지고있는 매핑은 꽤 큰 (2128 개 코드 포인트)이며, 그것은 단지 정규식 사용하는 것보다 훨씬 느리게 만들 수 있습니다

ranges = [(0, 8), (0xb, 0x1f), (0x7f, 0x84), (0x86, 0x9f), (0xd800, 0xdfff), (0xfdd0, 0xfddf), (0xfffe, 0xffff)] 
# fromkeys creates the wanted (codepoint -> None) mapping 
nukemap = dict.fromkeys(r for start, end in ranges for r in range(start, end+1)) 
clean = dirty.translate(nukemap) 
+1

몇 가지 테스트를 거친 후, 특히 큰 문자열의 경우 정규 표현식보다 훨씬 느린 것 같습니다. – itsadok

관련 문제