1

我想编写一个正则表达式来检查一个单词是否以除 s、x、y、z、ch、sh 或元音之外的任何内容结尾,然后是一个 s。这是我失败的尝试:

re.match(r".*[^ s|x|y|z|ch|sh|a|e|i|o|u]s",s)

补充一组字符的正确方法是什么?

4

4 回答 4

3

使用非正则表达式解决方案str.endswith

>>> from itertools import product
>>> tup = tuple(''.join(x) for x in product(('s','x','y','z','ch','sh'), 's'))
>>> 'foochf'.endswith(tup)
False
>>> 'foochs'.endswith(tup)
True
于 2013-11-13T09:45:49.583 回答
2
[^ s|x|y|z|ch|sh|a|e|i|o|u]

这是一个倒置字符类。字符类匹配单个字符,因此在您的情况下,它将匹配任何字符,除了以下之一:acehiosuxyz |. 请注意,它不会尊重诸如 and 之类的复合组chsh而 the|实际上被解释为在字符类中多次出现的管道字符(其中重复项被忽略)。

所以这实际上等价于下面的字符类:

[^acehiosuxyz |]

相反,您必须使用否定的外观来确保尾随s没有任何字符序列:

.*(?<!.[ sxyzaeiou]|ch|sh)s

这个有一个问题是它不能匹配两个字符词,因为要能够使用look behinds,look behinds需要有一个固定的大小。为了在后面的外观中同时包含单个字符和两个字符组,我必须在单个字符匹配中添加另一个字符。但是,您可以改用两个单独的外观:

.*(?<![ sxyzaeiou])(?<!ch|sh)s

正如 LarsH 在评论中提到的,如果你真的想匹配以此结尾的单词,你应该在表达式的末尾添加某种边界。如果你想匹配字符串/行的结尾,你应该添加一个$,否则你至少应该添加一个单词边界\b以确保单词实际上在那里结束

于 2013-11-13T09:54:22.677 回答
1

看起来您需要在这里进行负面回顾:

import re
rx = r'(?<![sxyzaeiou])(?<!ch|sh)s$'

print re.search(rx, 'bots')  # ok
print re.search(rx, 'boxs')  # None

请注意,re它不支持可变宽度的 LB,因此您需要其中的两个。

于 2013-11-13T09:53:44.850 回答
0

怎么样

re.search("([^sxyzaeiouh]|[^cs]h)s$", s)

使用search()而不是match()意味着匹配不必从字符串的开头开始,因此我们可以消除.*.

这是假设单词的结尾是字符串的结尾;即我们不必检查单词边界。

它还假设您不需要匹配 "word" hs,即使它在字面上符合您的规则。如果您也想匹配它,您可以添加另一种选择:

re.search("([^sxyzaeiouh]|[^cs]|^h)s$", s)

但同样,我们假设单词的开头是字符串的开头。

请注意,原始字符串符号 ,r"..."在这里是不必要的(但无害)。仅当您在正则表达式中有反斜杠时才有帮助,这样您就不必在字符串表示法中转义它们。

于 2013-11-13T09:51:19.223 回答