2016-04-19 2 views
2

Я использую следующий фрагмент текста, который содержит letter ü:Finding ü (и с умляут) с использованием регулярных выражений

test für fur test 

Вот код:

import re 

for m in re.finditer(r, line, re.IGNORECASE | re.UNICODE): 
    print 'match: ', m.group(0) 
    print 'offset: ', m.start() 

И есть три регулярные выражения:

r = ur'\bf(\u0075)r\b' # finds 'fur', as expected 
r = ur'\bf(\xc3\xbc)r\b' # finds 'für', as expected 
r = ur'\bf(\u00FC)r\b' # does not find 'für' 

Выражение # 1 и # 3 аналогичны; единственная разница - это точка Юникода (u - ü). Почему нет # 3?

Я могу использовать # 2, но это менее читаемо.

+0

Я только что сопоставил 'für' с вашим Regex 3. Не знаю, почему это не работает на вашей стороне. –

ответ

2

Вот мои результаты.

>>> print re.findall(ur'\bf(\u0075)r\b', "test für fur test", re.I|re.U) 
['u'] 
>>> print re.findall(ur'\bf(\xc3\xbc)r\b', "test für fur test", re.I|re.U) 
['\xc3\xbc'] 
>>> print re.findall(ur'\bf(\u00FC)r\b', "test für fur test", re.I|re.U) 
[] 

Они точно соответствуют вашим результатам. Я заметил, что матч для второго дела был ['\xc3\xbc'], затем он ударил меня. "test für fur test" - строка, отличная от юникода.

Здесь был мой второй набор тестов с юникодными строками.

>>> print re.findall(ur'\bf(\u0075)r\b', u"test für fur test", re.I|re.U) 
[u'u'] 
>>> print re.findall(ur'\bf(\xc3\xbc)r\b', u"test für fur test", re.I|re.U) 
[] 
>>> print re.findall(ur'\bf(\u00FC)r\b', u"test für fur test", re.I|re.U) 
[u'\xfc'] 

Регулярное выражение соответствует двоичному представлению в строке. Таким образом, строки unicode соответствуют символам Юникода, а строки, отличные от юникода, соответствуют кодированным символам UTF-8.


Если у вас нет выбора, как к типу жала вы работаете с, вы всегда можете использовать unicode().

>>> print re.findall(ur'\bf(\u00FC)r\b', unicode("test für fur test", "utf-8"), re.I|re.U) 
[u'\xfc'] 

В вашем случае

for m in regex.finditer(r, unicode(line, "utf-8"), regex.IGNORECASE | regex.UNICODE): 
    print 'match: ', m.group(0) 
    print 'offset: ', m.start() 

ПРИМЕЧАНИЕ

В зависимости от файла кодировки вашего .py файла, ur'\bf(ü)r\b' должны также работать.

>>> print re.findall(ur'\bf(ü)r\b', u"test für fur test", re.I|re.U) 
[u'\xfc'] 
2

Я думаю, вы сбиваете с толку себя здесь. Строки, которые вы используете grepping, по-видимому, не являются строками Unicode.

Если бы они были, вы бы получили \u00fc, как ожидалось.

>>> import re 
>>> m = re.search(ur'f(\xc3\xbc|\u0075|\u00fc)r', u'für') 
>>> m.group(1) 
u'\xfc' 

Вам все равно придется учитывать эквивалентность Юникода. Полностью разложенный эквивалент U+00FC является обычным u, а затем COMBINING DIAERESIS (U+0308). Вероятно, вы захотите запустить unicodedata.normalize('NFC', thing) и убедитесь, что ваше регулярное выражение всегда ищет составленный эквивалент (или, наоборот, идет по 'NFD' и полностью разлагается); или, возможно, переключиться на regex module, который, как утверждается, лучше справляется с этим.

Если вы имеете дело с UTF-8 и знаете, что это так, обычно рекомендуется декодировать его в строку Unicode, как только вы прочитаете его на Python. См. E.г. http://nedbatchelder.com/text/unipain.html

+0

Ты абсолютно прав. У меня есть класс UnicodeReader для того, что я не использовал в этот раз, потому что я только хотел проверить регулярное выражение с немецкими диакритическими символами. –

+0

Я пытался сопоставить 'u'f \ u00fcr'' с' u'fu \ u0308r'' с 'regex', и он тоже не соответствовал. Может быть, я что-то пропускаю. – tripleee

Смежные вопросы