Шаблон поиска, включающий квадратные скобки

Я пытаюсь найти точные слова в файле. Я читаю файл по строкам и перебираю строки, чтобы найти точные слова. Поскольку ключевое слово in не подходит для поиска точных слов, я использую шаблон регулярного выражения.

def findWord(w):
    return re.compile(r'\b({0})\b'.format(w), flags=re.IGNORECASE).search

Проблема с этой функцией в том, что она не распознает квадратные скобки [xyz].

Например

findWord('data_var_cod[0]')('Cod_Byte1 = DATA_VAR_COD[0]') 

возвращает None тогда как

findWord('data_var_cod')('Cod_Byte1 = DATA_VAR_COD') 

возвращает <_sre.SRE_Match object at 0x0000000015622288>

Может ли кто-нибудь помочь мне настроить шаблон регулярного выражения?


person BitsNPieces    schedule 21.07.2015    source источник
comment
Что вы ожидаете, что он вернется?   -  person Burhan Khalid    schedule 21.07.2015


Ответы (3)


Это из-за того, что механизм регулярных выражений предполагает, что квадратные скобки являются классом символов, которые являются символами регулярных выражений, чтобы избавиться от этой проблемы, вам нужно избежать ваших символов регулярных выражений. вы можете использовать функцию re.escape:

def findWord(w):
    return re.compile(r'\b({0})\b'.format(re.escape(w)), flags=re.IGNORECASE).search

Кроме того, как более питонический способ получить все совпадения, вы можете использовать re.fildall() который возвращает список совпадений или re.finditer который возвращает итератор, содержащий объекты соответствия.

Но все же этот способ не является полным и эффективным, потому что, когда вы используете границу слова, ваше внутреннее слово должно содержать символы одного типа.

>>> ss = 'hello string [processing] in python.'  
>>>re.compile(r'\b({0})\b'.format(re.escape('[processing]')),flags=re.IGNORECASE).search(ss)
>>> 
>>>re.compile(r'({})'.format(re.escape('[processing]')),flags=re.IGNORECASE).search(ss).group(0)
'[processing]'

Поэтому я предлагаю удалить границы слов, если ваши слова не содержат символов слова.

Но в качестве более общего способа вы можете использовать следующее регулярное выражение, которое использует положительный обзор, который соответствует словам которые окружают пробел или идут в конце строки или в начале:

r'(?: |^)({})(?=[. ]|$) '
person kasravnd    schedule 21.07.2015
comment
Здравствуйте, он по-прежнему возвращает None для: findWord('data_var_cod[0]')('Cod_Byte1 = DATA_VAR_COD[0]') - person BitsNPieces; 21.07.2015
comment
@BitsNPieces Привет;) ты убрал границы слов? - person kasravnd; 21.07.2015
comment
Да Работает после удаления границ! Большое спасибо :) - person BitsNPieces; 21.07.2015
comment
@BitsNPieces Добро пожаловать! - person kasravnd; 21.07.2015
comment
Привет, есть небольшая проблема после удаления границ. Теперь он соответствует последовательности символов, а не точным словам. Например, он возвращает true для findWord('data_var_cod[0]')('Cod_Byte1=DATA_VAR_COD[0]'), где предполагаемое поведение должно возвращать None, поскольку DATA_VAR_COD[0] не является отдельным словом! - person BitsNPieces; 21.07.2015
comment
@BitsNPieces Да, поставьте пробел в регулярном выражении! проверьте редактирование! - person kasravnd; 21.07.2015
comment
Привет, просмотр вокруг вызывает ошибку повышения ошибки, v # ошибка недопустимого выражения: просмотр назад требует шаблона фиксированной ширины - person BitsNPieces; 21.07.2015
comment
@BitsNPieces Поместите просмотр в группу без захвата и получите в результате первую группу (group(1)). - person kasravnd; 21.07.2015

Это потому, что [ и ] имеют особое значение. Вы должны указать строку, которую вы ищете:

re.escape(regex)

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

return re.compile(r'\b({0})\b'.format(re.escape(w)), flags=re.IGNORECASE).search
                                      ↑↑↑↑↑↑↑↑↑

Вы можете увидеть, что re.quote делает для вашей строки, например:

>>> w = '[xyz]'
>>> print re.escape(w)
\[xyz\]
person Maroun    schedule 21.07.2015
comment
Здравствуйте, он по-прежнему возвращает None для: findWord('data_var_cod[0]')('Cod_Byte1 = DATA_VAR_COD[0]') - person BitsNPieces; 21.07.2015

Вам нужен «умный» способ построения регулярного выражения:

def findWord(w):
    if re.match(r'\w', w) and re.search(r'\w$', w):
        return re.compile(r'\b{0}\b'.format(w), flags=re.IGNORECASE).search
    if not re.match(r'\w', w) and not re.search(r'\w$', w):
        return re.compile(r'{0}'.format(w), flags=re.IGNORECASE).search
    if not re.match(r'\w', w) and re.search(r'\w$', w):
        return re.compile(r'{0}\b'.format(w), flags=re.IGNORECASE).search
    if re.match(r'\w', w) and not re.search(r'\w$', w):
        return re.compile(r'\b{0}'.format(w), flags=re.IGNORECASE).search

Проблема в том, что некоторые из ваших ключевых слов будут иметь словесные символы только в начале, другие - только в конце, большинство из них будут иметь словесные символы на обоих концах, а некоторые будут содержать несловесные символы. Чтобы эффективно проверить границу слова, вам нужно знать, присутствует ли символ слова в начале/конце ключевого слова.

Таким образом, с помощью re.match(r'\w', x) мы можем проверить, начинается ли ключевое слово с символа слова, и если да, добавить \b к шаблону, а с помощью re.search(r'\w$', x) мы можем проверить, заканчивается ли ключевое слово символом слова.

Если у вас есть несколько ключевых слов для проверки строки, вы можете проверить этот мой пост.

person Wiktor Stribiżew    schedule 21.07.2015