Страницы

Поиск по вопросам

понедельник, 14 января 2019 г.

Не работает базовый метод строки и поиск по строке регулярным выражением

Есть очень примитивный код:
#!/usr/bin/python # -*- coding: utf-8 -*- import re from string import *
text = 'тут будет внедорожник (Туссан, туарег) или Ровер' text = text.lower() #text = text.decode('utf-8') print text
model_list = ['туссан', 'туарег', 'королла', 'нексия']
for model in model_list: response = re.search(model, text, re.IGNORECASE) if response: print 'найдено: ' + response.group(0)
Задача простая - есть список моделей и есть строка текста, по каждой модели списка надо найти вхождение в строку, и вот тут-то проблема:
данный код в том виде как выше в консоли пишет
тут будет внедорожник (Туссан, туарег) или Ровер найдено: туарег
а должен найти явно два авто
если задать переменную так text = u'тот же самый текст ...' или строку text = text.lower() переписать как text = text.decode('utf-8').lower(), то тогда в консоли уже следующее:
тут будет внедорожник (туссан, туарег) или ровер
т.е. регистр стал нижним, но при этом поиск не происходит. Более того, не понятно, почему re.I (или re.IGNORECASE) вообще не работает. Пробовал дописать re.I|re.U|re.S|re.M, ничего не выходит.
В чем тут проблема? Мне всего лишь надо проверить несколько слов в куске текста, при этом без учета регистра.


Ответ

Проблема в кодировке. Вы можете решить её несколькими способами (отсортированно по моему субъективному восприятию удобства способов):
Перейти на Python 3
В Python 3 по умолчанию используются юникодные литералы, поэтому у вас не возникнет подобных проблем. В коде при этом достаточно использовать функцию print вместо оператора, т.е. добавить скобки вызова функции:
import re
text = 'тут будет внедорожник (Туссан, туарег) или Ровер' model_list = ['туссан', 'туарег', 'королла', 'нексия']
for model in model_list: response = re.search(model, text, re.IGNORECASE) if response: print('найдено: ' + response.group(0))
Заметьте также, что нам нет необходимости в Python 3 вручную указывать кодировку файла исходного кода: в Python 3 по умолчанию используется кодировка utf-8. Вставить в начале файла строку
from __future__ import unicode_literals
Эта строка говорит, что в файле все строковые литералы будут иметь тип unicode. Особенно удобно использовать эту возможность для того, чтобы писать переносимый между версиями Python код (в сочетании с остальными возможностями модуля __future__). Выглядеть это будет следующим образом:
# coding: utf-8
from __future__ import unicode_literals import re
text = 'тут будет внедорожник (Туссан, туарег) или Ровер' model_list = ['туссан', 'туарег', 'королла', 'нексия']
for model in model_list: response = re.search(model, text, re.IGNORECASE | re.UNICODE) if response: print 'найдено: ' + response.group(0) Преобразовать используемые строки в юникод. Так вышло, модуль регулярных выражений некорректно обрабатывает кириллицу в байтовых строках (не умеет искать без учёта регистра). Вы можете вызвать преобразование в юникодные строки для нужных переменных:
# coding: utf-8
import re
text = 'тут будет внедорожник (Туссан, туарег) или Ровер' model_list = ['туссан', 'туарег', 'королла', 'нексия']
text = text.decode('utf-8')
for model in model_list: model = model.decode('utf-8') response = re.search(model, text, re.IGNORECASE | re.UNICODE) if response: print u'найдено: ' + response.group(0)
Заметьте, что при выводе результата, строка u'найдено' помечена юникодной. Это важно, потому что складывать можно только строки одного типа, а response.group(0) возвращает нам юникодную строку.
Использовать юникодные литералы вручную: (бывший способ №3)
# coding: utf-8
import re
text = u'тут будет внедорожник (Туссан, туарег) или Ровер' model_list = [u'туссан', u'туарег', u'королла', u'нексия']
for model in model_list: response = re.search(model, text, re.IGNORECASE | re.UNICODE) if response: print u'найдено: ' + response.group(0)

Важно заметить, что при правильном учёте кодировок строк можно пользоваться поиском без учёта регистра, но необходимо добавить флаг re.UNICODE для того, чтобы модуль правильно отрабатывал на юникодных строках.
Также старайтесь в новых проектах использовать Python 3, если нет строгих требований использовать версию Python 2.

Комментариев нет:

Отправить комментарий