Как сопоставить целое слово с регулярным выражением?

#python #regex #filter #selection

Вопрос:

У меня возникли проблемы с поиском правильного регулярного выражения для приведенного ниже сценария:

Давайте скажем:

 a = "this is a sample"
 

Я хочу сопоставить целое слово — например, совпадение "hi" должно возвращать значение False, так "hi" как это не слово, и "is" должно возвращать значение True, так как слева и справа нет альфа-символа.

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

1. Я снова открыл этот вопрос, потому что он был закрыт как дубликат с неправильным сообщением.

Ответ №1:

Попробуй

 re.search(r'bisb', your_string)
 

Из документов:

b Соответствует пустой строке, но только в начале или конце слова.

Обратите внимание, что re модуль использует наивное определение «слова» как «последовательности буквенно-цифровых символов или символов подчеркивания», где «буквенно-цифровой» зависит от локали или параметров юникода.

Также обратите внимание, что без префикса необработанной строки b отображается как «backspace» вместо границы слова регулярного выражения.

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

1. Спасибо, я добавил флаги=re. ИГНОРИРОВАНИЕ

2. для чего нужен r в этом операторе — повторный поиск( r ‘bisb’, your_string) ?

3. @user2161049: test! это не слово, по любому определению, которое я знаю. Интересно, что это действительно работает для сокращений: re.search(r"bisn'tb", "it isn't bad") возвращает совпадение.

4. Как ни странно, это не работает для терминалов: re.search(r"bisn'b", "it isn' bad") не возвращает совпадения. Особенным является не апостроф, а расположение. Слово (шаблон) может иметь знак препинания внутри, но не в конце или начале. test!a может соответствовать чему-то, но test! не может.

5. Почему я получил x08 вместо b этого ?

Ответ №2:

Попробуйте использовать класс символов «граница слова» в модуле регулярных выражений, re :

 x="this is a sample"
y="this isis a sample."
regex=re.compile(r"bisb")  # For ignore case: re.compile(r"bisb", re.IGNORECASE)

regex.findall(y)
[]

regex.findall(x)
['is']
 

Из документации re.search() .

b соответствует пустой строке, но только в начале или конце слова

Например r'bfoob' , совпадения 'foo' , 'foo.' , '(foo)' , 'bar foo baz' но не 'foobar' или 'foo3'

Ответ №3:

Я думаю, что поведение, желаемое ОП, не было полностью достигнуто с помощью данных ответов. В частности, желаемый вывод логического значения не был выполнен. Приведенные ответы действительно помогают проиллюстрировать концепцию, и я думаю, что они превосходны. Возможно, я могу проиллюстрировать то, что я имею в виду, заявив, что я думаю, что ОП использовала примеры, использованные из-за следующего.

Приведенная строка была,

a = "this is a sample"

Затем ОП заявил,

Я хочу сопоставить целое слово — например, совпадение "hi" должно возвращаться False , так "hi" как это не слово …

Как я понимаю, ссылка относится к маркеру поиска, "hi" как он содержится в слове, "this" . Если кто-то будет искать в строке a слово "hi" , оно должно быть получено False в качестве ответа.

Операция продолжается,

… и "is" должен вернуться True , так как слева и справа нет альфа-символа.

В этом случае ссылка относится к маркеру поиска "is" , поскольку он находится в слове "is" . Я надеюсь, что это поможет прояснить вопрос о том, почему мы используем границы слов. Другие ответы ведут себя так: «не возвращайте слово, если это слово не найдено само по себе, а не внутри других слов». Класс сокращенных символов «граница слов» прекрасно справляется с этой задачей.

"is" До этого момента в примерах использовалось только это слово. Я думаю, что эти ответы верны, но я думаю, что есть еще один фундаментальный смысл вопроса, который необходимо рассмотреть. Чтобы понять концепцию, следует обратить внимание на поведение других строк поиска. Другими словами, нам нужно обобщить (отличный) ответ @georg, используя re.match(r"bisb", your_string) Та же r"bisb" концепция также используется в ответе @OmPrakash, который начал обобщающее обсуждение, показав

 >>> y="this isis a sample."
>>> regex=re.compile(r"bisb")  # For ignore case: re.compile(r"bisb", re.IGNORECASE)
>>> regex.findall(y)
[]
 

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

 find_only_whole_word(search_string, input_string)
 

Тогда следует ожидать следующего поведения.

 >>> a = "this is a sample"
>>> find_only_whole_word("hi", a)
False
>>> find_only_whole_word("is", a)
True
 

Еще раз, вот как я понимаю вопрос ОП. У нас есть шаг к такому поведению с ответом от @georg , но его немного сложно интерпретировать/реализовать. а именно

 >>> import re
>>> a = "this is a sample"
>>> re.search(r"bisb", a)
<_sre.SRE_Match object; span=(5, 7), match='is'>
>>> re.search(r"bhib", a)
>>>
 

Из второй команды нет выходных данных. Полезный ответ от @OmPrakesh показывает результат, но не True или False .

Вот более полная выборка ожидаемого поведения.

 >>> find_only_whole_word("this", a)
True
>>> find_only_whole_word("is", a)
True
>>> find_only_whole_word("a", a)
True
>>> find_only_whole_word("sample", a)
True
# Use "ample", part of the word, "sample": (s)ample
>>> find_only_whole_word("ample", a)
False
# (t)his
>>> find_only_whole_word("his", a)
False
# (sa)mpl(e)
>>> find_only_whole_word("mpl", a)
False
# Any random word
>>> find_only_whole_word("applesauce", a)
False
>>>
 

Это может быть достигнуто с помощью следующего кода:

 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
#@file find_only_whole_word.py

import re

def find_only_whole_word(search_string, input_string):
  # Create a raw string with word boundaries from the user's input_string
  raw_search_string = r"b"   search_string   r"b"

  match_output = re.search(raw_search_string, input_string)
  ##As noted by @OmPrakesh, if you want to ignore case, uncomment
  ##the next two lines
  #match_output = re.search(raw_search_string, input_string, 
  #                         flags=re.IGNORECASE)

  no_match_was_found = ( match_output is None )
  if no_match_was_found:
    return False
  else:
    return True

##endof:  find_only_whole_word(search_string, input_string)
 

Далее следует простая демонстрация. Запустите интерпретатор Python из того же каталога, в котором вы сохранили файл, find_only_whole_word.py .

 >>> from find_only_whole_word import find_only_whole_word
>>> a = "this is a sample"
>>> find_only_whole_word("hi", a)
False
>>> find_only_whole_word("is", a)
True
>>> find_only_whole_word("cucumber", a)
False
# The excellent example from @OmPrakash
>>> find_only_whole_word("is", "this isis a sample")
False
>>>
 

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

1. Обратите внимание, что, если требуются только «истинные» целые слова, входные данные должны быть очищены. >>> find_only_whole_word("another sentence", "To show this, I will use another sentence.") ВОЗВРАТ True . Возможно, это желаемое поведение, поэтому я оставляю свой ответ как есть.

2. Если вы хотите однострочный, используя findall метод, используемый @OsPrakesh: >>> len(re.findall(r"bhib", "This IS a sample.", flags=re.IGNORECASE)) возвращает False . Любые другие нужные строки могут быть вставлены между b буквами s.

Ответ №4:

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

Этот код позволит найти слово

  word="is"
    srchedStr="this is a sample"
    if srchedStr.find(" " word " ") >=0  or 
       srchedStr.endswith(" " word):
        <do stuff>
 

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

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

1. Кроме того, я вижу, что уже был принят ответ — возможно, вы захотите удалить свой ответ и восстановить репутацию из-за пониженного голоса.

2. @davejagoda восстановит ли удаление ответа его/ее репутацию?

3. @silentphoenix Я так считаю: meta.stackexchange.com/questions/5221/…

4. Первый абзац неверен. Целевая строка может содержать произвольное содержимое.

5. Это не сработает, если слово появляется в начале целевой строки. Это также предполагает, что слова всегда окружены пробелами, что в целом неверно.