如何让Python正则表达式将梵文(Devanagiri)Unicode块U+0900至U+097F全部视为单词字符?
我来帮你搞定这个正则的问题!首先得弄明白为啥你的पानी匹配不到——Python标准库的re模块里,默认的\b(单词边界)是纯ASCII逻辑的:它只把英文字母、数字和下划线当成“单词字符”,完全不认识梵文(天城文)的字符。
你看,पानी里的每个字符都不在ASCII单词字符范围内,当正则检查结尾的\b时,它会发现ी不是\w(默认的单词字符),后面的空白也不是\w,两个非单词字符之间自然触发不了\b的匹配,所以पानी就被漏掉了。
下面给你两种解决思路,一种不用装第三方库,一种更简洁:
方法一:用标准re模块,手动自定义单词边界
如果不想额外装库,我们可以完全抛弃默认的\b,自己定义“什么是单词字符”——把ASCII单词字符(a-zA-Z0-9_)加上梵文区块\u0900-\u097F都算进去,然后写自定义的边界检查:
把你的正则改成这样:
(?<!\.)(?<![\u0900-\u097Fa-zA-Z0-9_])(a(?:bc|de)|zip|चाय|पानी)(?![\u0900-\u097Fa-zA-Z0-9_])
我给你拆解下各部分的作用:
(?<!\.):和你原来的逻辑一致,确保匹配的词前面不是点号(?<![\u0900-\u097Fa-zA-Z0-9_]):负向后预查,保证匹配的词前面不是我们定义的“单词字符”(梵文+ASCII单词字符)- 中间的
(a(?:bc|de)|zip|चाय|पानी):你原本要匹配的目标词 (?![\u0900-\u097Fa-zA-Z0-9_]):负向前预查,保证匹配的词后面不是我们定义的“单词字符”
测试一下代码:
import re result = re.findall(r'(?<!\.)(?<![\u0900-\u097Fa-zA-Z0-9_])(a(?:bc|de)|zip|चाय|पानी)(?![\u0900-\u097Fa-zA-Z0-9_])', 'This is abc, ade, चाय, पानी and abca') print(result) # 输出:['abc', 'ade', 'चाय', 'पानी']
这样就能正确匹配到पानी了。
方法二:用regex第三方库(更简洁推荐)
Python标准re对Unicode的支持确实有限,第三方的regex模块专门解决这类问题,用起来更省心。
首先先安装它:
pip install regex
然后你只需要开启UNICODE_WORD标志,\w就会自动包含所有Unicode字母(包括梵文),原来的\b也会基于这个扩展的单词字符来判断边界,完全不用改原来的正则结构:
测试代码:
import regex result = regex.findall(r'(?<!\.)(a(?:bc|de)|zip|चाय|पानी)\b', 'This is abc, ade, चाय, पानी and abca', flags=regex.UNICODE_WORD) print(result) # 输出:['abc', 'ade', 'चाय', 'पानी']
是不是简单多了?这个模块还支持\p{Devanagari}这样的Unicode属性类,如果你想更精准地只针对梵文区块,也可以用它来定义单词字符,比如把\w替换成[\p{Devanagari}a-zA-Z0-9_],不过开启UNICODE_WORD已经能满足你的需求了。
总结一下:核心就是明确你要把哪些字符当成单词字符,然后要么手动写边界检查,要么用对Unicode更友好的regex模块来简化操作。
备注:内容来源于stack exchange,提问作者ACBlue

