2009-11-10 21 views
23

XML specification, yasa dışı veya "cesareti kırılmış" bir grup Unicode karakterini listeler. Bir dize verildiğinde, tüm yasadışı karakterleri nasıl kaldırabilirim?Python'da yasa dışı xml unicode karakterleri filtrelemenin hızlı yolu?

Aşağıdaki normal ifadeyle ortaya çıktım, ama biraz da ağız dolusu.

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) 

(Python 2.5, 0xFFFF yukarıda Unicode karakter hakkında o filtrelemek için çok gerek bilmiyor.) Ayrıca, seçilen codepoints silmek yöntemini çevirmek unicode kullanabilirsiniz

+0

Python'un maksimum unicode kod noktası, derlendiğinde nasıl yapılandırıldığına bağlı olarak, 'sys.maxunicode' seçeneğini işaretleyin. – u0b34a0f6ae

+0

Haklısınız. Sanırım daha da karmaşık. – itsadok

+2

Makinemde, 2.3mb'lik bir dizeyi işlemek için bu normal ifadeyi kullanarak .34 saniye sürüyor. Bu bana oldukça hızlı geliyor. –

cevap

11

Son zamanlarda (Trac XmlRpcPlugin sürdürücüler) Aslında haberdar edildiğini düzenli ifade Python dar yapıdaki şeritler üzerinde çiftler (bkz. th:comment:13:ticket:11050). Alternatif bir yaklaşım, aşağıdaki regex kullanımından oluşur (bkz. 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. Ne için olduklarını açıklayan this post on surrogates numaralı telefona bakın.

Güncelleme yüzden maç için değil gibi bir valid XML character olduğunu 0x0D (değiştirin).

+0

Vekil çiftlerin W3C XML belirtimindeki yasal karakterlerden açıkça hariç tutulduğunu unutmayın, böylece bunları içeren herhangi bir xml, diğer kitaplıklarda doğru şekilde ayrıştırılması garanti edilmez. Ancak, genellikle XML'i utf-8 veya utf-16'ya serileştireceğinizden, sorun ortadan kalkmalıdır. Sadece utf-32'den uzaklaş. – itsadok

+0

0x0D karakteriyle eşleşen regex'i güncelledim. [Th: ticket: 11635] (http://trac-hacks.org/ticket/11635), [th: changeset: 13776] (http://trac-hacks.org/changeset/13776) ve [XML karakteri] konusuna bakın. aralık tanımı] (http://www.w3.org/TR/REC-xml/#NT-Char). –

+0

İyi nokta. Sürümümü de güncelledim. – itsadok

3

. Ancak, sahip haritalama oldukça büyük (2128 codepoints) 'dir ve bu sadece bir normal ifade kullanmaktan daha çok daha yavaş olmasına neden olabilir:

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

Bazı testlerden sonra, bu özellikle büyük dizeler için bir regexp'den çok daha yavaş görünüyor. – itsadok

İlgili konular