如何使用正则表达式匹配整个单词?

70

我很难找到适用于以下场景的正确正则表达式:

假设有:

a = "this is a sample"

我希望匹配整个单词 - 例如,匹配"hi"应该返回False,因为"hi"不是一个单词,而"is"应该返回True,因为左右两侧没有字母字符。

4个回答

92
尝试
re.search(r'\bis\b', your_string)

来自文档

\b匹配一个空字符串,但只在单词的开头或结尾。

请注意,re模块将“单词”简单定义为“字母数字或下划线字符序列”,其中“字母数字”取决于区域设置或Unicode选项。

还要注意,如果没有使用原始字符串前缀,\b将被视为“退格”而不是正则表达式中的单词边界。


3
谢谢,我添加了 flags=re.IGNORECASE。 - user2161049
3
这个语句中的 r 是干什么用的?re.search(r'\bis\b', your_string) - swordholder
@user2161049: test!并不是我所知道的任何一个定义中的词。有趣的是,它对于缩略词是有效的:re.search(r"\bisn't\b", "it isn't bad")会返回匹配。 - Jeff Learman
奇怪的是,它不能用于终端省略:re.search(r"\bisn'\b", "it isn' bad")没有匹配结果。这不是撇号特殊,而是位置特殊。单词(模式)可以在内部具有标点符号,但不能在开头或结尾。test!a可以匹配某些内容,但test!则无法。 - Jeff Learman
为什么我得到了\x08而不是\b - Peter.k
如果bis保存在一个变量中,如何使其工作?foo =“bis” re.search("\ b"+ foo +"\ b", your_string)无法正常工作。 - Arteezy

8
尝试在正则表达式模块re中使用“单词边界”字符类:
x="this is a sample"
y="this isis a sample."
regex=re.compile(r"\bis\b")  # For ignore case: re.compile(r"\bis\b", re.IGNORECASE)

regex.findall(y)
[]

regex.findall(x)
['is']

以下是re.search()文档中的内容:

\b匹配空字符串,但只能在单词的开头或结尾处匹配。

...

例如,r'\bfoo\b'可以匹配'foo''foo.''(foo)''bar foo baz',但不能匹配'foobar''foo3'


3
我认为使用现有答案并没有完全实现OP所需的行为。具体来说,并未实现布尔值的预期输出。给出的答案确实帮助了解该概念,我认为它们非常好。也许我可以通过以下方式说明我的意思,我认为OP使用了以下示例,因为:

给定字符串为,

a = "this is a sample"

然后OP陈述道,

我想匹配整个单词,例如匹配 "hi" 应返回 False,因为 "hi" 不是一个单词...

据我所知,引用是搜索标记 "hi" 在单词 "this" 中找到的情况。如果有人在字符串 a 中搜索单词 "hi",他们应该收到 False 作为响应。

OP继续说,

... 而 "is" 应返回 True,因为左侧和右侧都没��字母字符。

在这种情况下,引用是搜索标记 "is" 在单词 "is" 中找到的情况。我希望这有助于澄清为什么我们使用单词边界的事情。其他答案的行为是“除非该单词单独出现,否则不返回单词 - 不在其他单词内部。” “单词边界” 简写字符类 很好地完成了这项工作。

到目前为止,只使用了单词 "is" 的示例。我认为这些答案是正确的,但我认为还需要处理更多问题的基本含义。应注意其他搜索字符串的行为以了解该概念。换句话说,我们需要通过使用re.match(r"\bis\b", your_string)概括 @georg的(优秀)答案。同样的r"\bis\b" 概念也用于@OmPrakash的答案中,他通过展示开始泛化讨论来完成这一点。

>>> y="this isis a sample."
>>> regex=re.compile(r"\bis\b")  # For ignore case: re.compile(r"\bis\b", 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

再次解释一下,我理解 OP 的问题是这样的。我们可以从 @georg 的答案中得到一些有助于实现这种行为的步骤,但这些步骤可能有些难以理解和实施。

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

第二个命令没有输出。有用的答案来自@OmPrakesh,但没有TrueFalse

这里是更完整的预期行为示例。

>>> 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)

以下是一个简单的演示。在保存了文件find_only_whole_word.py的同一目录中运行Python解释器。

>>> 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
>>>

请注意,如果只需要“true”整个单词,则必须对输入进行清理。>>> find_only_whole_word("another sentence", "To show this, I will use another sentence.") 返回 True。这可能是期望的行为,因此我将保留我的答案。 - bballdave025
如果您想使用@OsPrakesh使用的findall方法来编写一行代码:>>> len(re.findall(r"\bhi\b", "This IS a sample.", flags=re.IGNORECASE)) 返回 False。任何其他所需的字符串都可以放在\b之间。 - bballdave025

-9
正则表达式的问题在于,如果你想在另一个字符串中搜索的字符串具有正则表达式字符,那么它会变得复杂。任何带括号的字符串都将失败。
这段代码将找到一个单词。
 word="is"
    srchedStr="this is a sample"
    if srchedStr.find(" "+word+" ") >=0  or \
       srchedStr.endswith(" "+word):
        <do stuff>

条件语句的第一部分查找两侧都有空格的文本,而第二部分则捕获字符串结尾的情况。请注意,endwith 是布尔型,而 find 返回一个整数。


1
另外,我看到已经有一个被接受的答案了 - 你可能想要删除你的答案并恢复因为负评而失去的声望。 - davejagoda
@davejagoda 删除答案会恢复他/她的声誉吗? - Joseph Farah
2
@silentphoenix 我相信是这样的:http://meta.stackexchange.com/questions/5221/how-does-deleting-work-what-can-cause-a-post-to-be-deleted-and-what-does-that - davejagoda
第一个段落是不正确的。目标字符串可以有任意内容。 - Basilevs
如果单词出现在目标字符串的开头,那么这种方法就不起作用了。它还假设单词总是被空格包围,但这并不总是正确的。 - melpomene

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接