我试图在句子中找到一个模式的索引。模式可以是一个单词或单词的组合。我已经为此使用了正则表达式。但我有一些棘手的案子要处理。
import re
word = "is"
s = "Is (valid) is (valid), is-not (not valid), is. (valid) is!, (valid), is_1 (not valid) ,is (valid), is? (valid)"
iters = re.finditer(r"b" + re.escape(word) + r"b", s, re.I)
indices = [m.start(0) for m in iters]
print(indices)
此输出
[0, 11, 23, 43, 55, 87, 99]
正如您所看到的,is
与某些符号的出现是必需的匹配,而有些则不是。以下是匹配时可以考虑的有效符号列表。
[" ", ",", ".", "!", "?"]
如何从结果中避免第三次匹配(is-not
(?
您的问题有点模棱两可,因为您将一些特定字符指定为边界字符(而不是将任何非单词字符指定为边缘字符(,但您使用的是"\b";代码中的单词边界断言(使用任何非单词字符作为边界字符(。因此,我不能确定你是否只是想调整";\b";不考虑"-"作为边界字符,或者如果您想重写正则表达式以完全使用问题中指定的边界字符。
为了调整";\b";忽略"-"作为一个边界字符,你可以使用一个负的后向断言和一个负向前断言(基本上说,"除非边界是由短划线引起的"(,所以你的代码只有一行会改变:
iters = re.finditer(r"(?<!-)b" + re.escape(word) + r"b(?!-)", s, re.I)
此更改导致输出变为
[0, 11, 43, 55, 87, 99]
这似乎正是你想要的。请记住,还有其他非单词字符(除了您提到的字符(会导致正则表达式匹配(在通用字符串中,而不是您提供的字符串(。
我现在不打算提供一个正则表达式来处理您指定的字符,因为您的示例代码使用了";\b";暗示你想使用它,但只是不考虑"-"作为边界字符(因此也意味着您列出的边界字符主要来自您的示例,并且没有使列表包罗万象(。
如果在之后搜索all is nots,则可以检查哪些值在其中,而不是在另一个中。
indices_is = [m.start(0) for m in iters_is]
然后你再次运行该代码并获得
indices_isnot = [m.start(0) for m in iters_isnot]
Real is列表:
indices_is = [i for i in indeces_is if i not in indices_isnot]
如果您能够清楚地定义不允许使用的单词边界字符(在您提供的示例中,它只能是短划线字符(-
((,那么一个简单的、仅使用正则表达式的解决方案可以包含负向后看和负向前看的概念:
pattern = r"(?<!-)b" + re.escape(word) + r"b(?!-)"
这个正则表达式背后的想法是匹配由单词边界包围的单词的每个实例(正如您已经做的那样(,除非单词前面或后面有破折号。你也可以考虑使用正向后向和前向,即不是定义不允许的字符列表,而是定义允许在模式之前或之后的字符列表。我之所以提到这一点,是因为你在问题中提供了允许使用的字符列表;然而,由于lookbehind/lookahead的限制,我不知道使用这种方法的解决方案也可以解释单词位于行的开头或末尾的可能性。