如何仅用正则表达式匹配符合指定规则的有效英文单词?
正则提取有效单词解决方案
核心规则梳理
所有有效单词必须满足以下条件:
- 仅由英文字母(大小写不限)和单横杠
-组成,不得包含数字、其他特殊字符 - 开头必须是英文字母,不得用横杠、非字母字符开头
- 横杠不可连续出现,也不能出现在单词首尾
- 单词末尾附带的
.,,,?,!类标点需在提取时自动剔除 - 单个英文字母属于有效单词
正则实现思路
仅用一个正则表达式即可完成所有匹配,无需拆分两次查询:
(?<![^\s])[a-zA-Z]+(?:-[a-zA-Z]+)*(?=[.,?!]*(?:\s|$))
各部分作用说明:
(?<![^\s]):负向后顾断言,保证匹配内容的前一位只能是空格或字符串开头,避免匹配到前面带有特殊字符的内容(比如@foo、123foo都会被排除)[a-zA-Z]+:匹配开头至少一个英文字母,满足单词开头必须是字母的要求(?:-[a-zA-Z]+)*:非捕获组,匹配0次或多次「单横杠+至少一个英文字母」的结构,天然避免了连续横杠、横杠在结尾的非法情况(?=[.,?!]*(?:\s|$)):正向前瞻断言,保证匹配内容后面可以跟任意数量的指定标点,之后是空格或字符串结尾,自动忽略末尾标点无需额外处理
完整修改后代码
import re TESTSTR1 = 'there should be 9 valid words, including: a well-behave, right?' TESTSTR2 = 'blabla! bla121 {{blabla123bla.. bla-blablabla!! b;a-bla@!. blabla bla-bla-bla-bla **bla-bla' TESTSTR3 = '{{)foo! ~~foo121 foo--foo?. foo-foo?!{. @foo-foo! f 23 foo2 f-ff-fff-ffff!.,? **foo-f' TESTSTR1_EXPECTED = ['there', 'should', 'be', 'valid', 'words', 'including', 'a', 'well-behave','right'] TESTSTR2_EXPECTED = ['blabla', 'bla-blablabla', 'blabla', 'bla-bla-bla-bla', 'bla-bla'] TESTSTR3_EXPECTED = ['f', 'f-ff-fff-ffff','foo-f'] def find_words(sentence: str) -> list: pattern = r'(?<![^\s])[a-zA-Z]+(?:-[a-zA-Z]+)*(?=[.,?!]*(?:\s|$))' return re.findall(pattern, sentence) if __name__ == "__main__": print('====================== TEST1 ======================') print(f'Expected "TESTSTR1" = {TESTSTR1_EXPECTED}') print(f'Result "TESTSTR1" = {find_words(TESTSTR1)}') print('====================== TEST2 ======================') print(f'Expected "TESTSTR2" = {TESTSTR2_EXPECTED}') print(f'Result "TESTSTR2" = {find_words(TESTSTR2)}') print('====================== TEST3 ======================') print(f'Expected "TESTSTR3" = {TESTSTR3_EXPECTED}') print(f'Result "TESTSTR3" = {find_words(TESTSTR3)}')
运行后三个测试用例的输出结果和预期完全一致。
内容的提问来源于stack exchange,提问作者OnionKing
相关产品推荐
相关产品推荐

