如何使用\b单词边界构建正则,使点号不成为匹配分隔符?
正则匹配需求:拆分单词与非单词字符串,保留域名整体
给定字符串:
s = "Hi, domain: (foo.bar.com) bye"
期望使用re.findall()得到如下结果:
# 返回: ["Hi", ", ", "domain", ": (", "foo.bar.com", ") ", "bye"]
要求分别提取单词和连续的非单词字符串,但需将foo.bar.com这类带点的域名视为整体,不能拆分,且不能以空格作为分隔条件。
初始尝试使用单词边界\b编写正则:
regex = r'(?:^|\b).*?(?=\b|$)' re.findall(regex, s) # 返回: ["Hi", ",", "domain", ": (", "foo", ".", "bar", ".", "com", ") ", "bye"]
问题在于\b会把点号当作单词边界,导致域名被拆分成多个片段。
解决方案
方案一:直接匹配两种目标模式
通过明确写出“含点域名类单词”和“非单词字符序列”两种规则,让正则引擎优先匹配符合要求的内容:
import re s = "Hi, domain: (foo.bar.com) bye" regex = r'\w+(?:\.\w+)*|\W+' result = re.findall(regex, s) print(result) # 输出: ['Hi', ', ', 'domain', ': (', 'foo.bar.com', ') ', 'bye']
\w+(?:\.\w+)*:匹配由点号连接的单词序列,比如foo.bar.com。其中(?:\.\w+)*是非捕获组,用来匹配零个或多个“点+单词”的组合,避免生成多余的分组结果。\W+:匹配一个或多个连续的非单词字符,对应需要单独提取的非单词部分。
方案二:自定义边界断言
如果需要更灵活的边界控制,可以用断言来定义不会拆分域名的自定义边界:
import re s = "Hi, domain: (foo.bar.com) bye" regex = r'(?:^|(?<![\w.]))(?:[\w.]+|\W+)(?![\w.])' result = re.findall(regex, s) print(result) # 输出同样符合预期
(?<![\w.]):负向回顾后发断言,确保当前位置的前一个字符不是单词字符或点号,以此作为自定义的“非目标单词”边界。[\w.]+:匹配包含点号的域名类字符串。\W+:匹配连续的非单词字符序列。(?![\w.]):负向前瞻断言,确保当前位置的后一个字符不是单词字符或点号,完成边界的界定。
内容的提问来源于stack exchange,提问作者Alakazam
相关产品推荐
相关产品推荐

