2013-04-21 99 views
2

我有這樣的代碼錯誤的字符集後應用re.sub()

import chardet, re  

content = "Бланк свидетельства о допуске." 
print content 
print chardet.detect(content) 
content = re.sub(u"(?i)[^-0-9a-zа-яё«»\&\;\/\<\>\.,\s\(\)\*:!\?]", "", content) 
print content 
print chardet.detect(content) 

和輸出

Бланк свидетельства о допуске. 
{'confidence': 0.99, 'encoding': 'utf-8'} 
� � . 
{'confidence': 0.5, 'encoding': 'windows-1252'} 

什麼,我做錯了什麼?如何在re.sub()之後獲得uft-8 str? (Python 2.7,# coding: utf-8,UTF-8文件,IDE Pycharm)。

謝謝。

+1

您試圖在原始字節上使用正則表達式嗎?您在*字節*上操作,而不是字符,每個輸入字符都由2個字節組成。 – 2013-04-21 11:35:21

+0

以及我如何獲得UTF-8? – 2013-04-21 11:37:21

+0

什麼是期望的輸出? – unutbu 2013-04-21 11:56:49

回答

5

這是(我覺得)你想實現(我已經簡化爲清晰起見,正則表達式):

#coding=utf8 
import re  
content = u"Бланк XYZ свидетельства о ???допуске." 
content = re.sub(u"(?iu)[^а-яё]", ".", content) 
print content.encode('utf8') # Бланк.....свидетельства.о....допуске. 

注意要點:

  • 的主題是unicode
  • 表達式是unicode
  • 該表達式使用unicode標誌(?u)進行大小寫摺疊工作。

此外,對於嚴重的unicode工作,我推薦使用regex模塊,該模塊提供出色且幾乎完整的unicode支持。試想一下:

# drop everything except Cyrillic and spaces 
import regex 
content = regex.sub(u'[^\p{Cyrillic}\p{Zs}]', '', content) 

雖然這是documentedre.UNICODE只有改變\w和朋友,在我的測試中,它也影響大小寫摺疊(re.IGNORECASE):

Python 2.7.2+ (default, Oct 4 2011, 20:06:09) 
[GCC 4.6.1] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import re 
>>> src = u'Σσ Φφ Γγ' 
>>> src 
u'\u03a3\u03c3 \u03a6\u03c6 \u0393\u03b3' 
>>> re.sub(ur'(?i)[α-ώ]', '-', src) 
u'\u03a3- \u03a6- \u0393-' 
>>> re.sub(ur'(?iu)[α-ώ]', '-', src) 
u'-- -- --' 

所以,這兩種無證功能或文檔的問題。

+0

're.IGNORECASE'的文檔聲明它不受區域設置的影響。 're.UNICODE'標誌被記錄爲僅改變字符類('\ w','\ W','\ s','\ S'等等。 – 2013-04-21 12:05:40

+0

感謝'正則表達式'模塊。 – 2013-04-21 12:07:01

+0

@MartijnPieters:爲我工作看到更新 – georg 2013-04-21 12:29:45

2

您的意見是UTF-8:

>>> content 
'\xd0\x91\xd0\xbb\xd0\xb0\xd0\xbd\xd0\xba \xd1\x81\xd0\xb2\xd0\xb8\xd0\xb4\xd0\xb5\xd1\x82\xd0\xb5\xd0\xbb\xd1\x8c\xd1\x81\xd1\x82\xd0\xb2\xd0\xb0 \xd0\xbe \xd0\xb4\xd0\xbe\xd0\xbf\xd1\x83\xd1\x81\xd0\xba\xd0\xb5.' 

但是,你正在使用的unicode 正則表達式。該表達式與您的UTF-8輸入的原始字節 直接匹配。

在所有這些字節中,只有空格,句號和\xbb字節(如»字符)不會被刪除。其餘的單個字節被刪除,因爲它們不屬於你的否定字符類[^...]

使用Unicode正確(通過解碼content爲Unicode第一)工作原理:

>>> re.sub(u"(?i)[^-0-9a-zа-яё«»\&\;\/\<\>\.,\s\(\)\*:!\?]", "", content.decode('utf8')) 
u'\u043b\u0430\u043d\u043a \u0441\u0432\u0438\u0434\u0435\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u0430 \u043e \u0434\u043e\u043f\u0443\u0441\u043a\u0435.' 
>>> print re.sub(u"(?i)[^-0-9a-zа-яё«»\&\;\/\<\>\.,\s\(\)\*:!\?]", "", content.decode('utf8')) 
ланк свидетельства о допуске. 

另一種方法是使用原始的字節串的正則表達式,以及匹配字節組合。制定什麼UTF-8字節和範圍有效是非常,非常難。你需要完全瞭解如何UTF-8 encodes characters to multiple bytes,然後將你的負面字符類翻譯成一組積極的匹配,允許通過相同的字節組合。這是而不是爲心灰意懶。

+0

道歉,我意識到你的表達本身*是* unicode。你不應該混合這些。 – 2013-04-21 11:58:26