Golang 正则表达式支持 Unicode 字符的正确写法

2次阅读

Golang 正则表达式支持 Unicode 字符的正确写法

goregexp 包中 w 仅匹配 ASCII 字母数字和下划线,不支持 Cyrillic、Czech 等 Unicode 字母;需改用 Unicode 类 p{L} 并显式补充 d 和 _,才能正确提取多语言单词。

go 的 `regexp` 包中 `w` 仅匹配 ascii 字母数字和下划线,不支持 cyrillic、czech 等 unicode 字母;需改用 unicode 类 `p{l}` 并显式补充 `d` 和 `_`,才能正确提取多语言单词。

在 Go 中处理国际化文本时,正则表达式 w+ 常被误认为能匹配“所有语言的单词”,但事实并非如此。根据 Go 正则语法文档,w 是严格等价于 [0-9A-Za-z_] 的 ASCII-only 缩写,完全忽略 Unicode 字母(如俄语的 Раз、捷克语的 tři)。这导致 FindAllString 对含西里尔或带重音字符的文本返回空切片或错误切分(如将 tři 拆为 t i ty i)。

解决方法是使用 Unicode 字符类 p{L}(表示任意 Unicode 字母),并手动补全数字 d 和下划线 _,构成完整单词字符集:

package main  import (     "fmt"     "regexp" )  func getwordsFrom(text string) []string {     // ✅ 正确:支持所有 Unicode 字母 + 数字 + 下划线     re := regexp.MustCompile(`[p{L}d_]+`)     return re.FindAllString(text, -1) }  func main() {     text := "One, two three!"     text2 := "Раз, два три!"     text3 := "Jedna, dva tři čtyři pět!"      fmt.Println(getWordsFrom(text))  // [One two three]     fmt.Println(getWordsFrom(text2)) // [Раз два три]     fmt.Println(getWordsFrom(text3)) // [Jedna dva tři čtyři pět] }

? 补充说明:

  • p{L} 是 Unicode 通用类别(Unicode Category L),涵盖 Ll(小写字母)、Lu(大写字母)、Lt(首字母大写)、Lm(修饰字母)、Lo(其他字母)等全部子类,完美覆盖俄语、捷克语、中文(汉字属 p{Lo})、阿拉伯语等;
  • 若需排除数字,可简化为 [p{L}_]+;若需兼容连字符(如 state-of-the-art),可扩展为 [p{L}d_]+(?:-[p{L}d_]+)*;
  • 注意:Go 的 regexp 不支持 PCRE 风格的 w+u 或 (?u)w+,也不支持 p{Word} —— 必须显式组合 Unicode 类。

✅ 最佳实践建议:

立即学习go语言免费学习笔记(深入)”;

  • 永远避免在国际化场景中直接使用 w;
  • 使用 [p{L}d_]+ 作为默认“单词”模式;
  • 如需更严谨的分词(例如处理标点粘连、缩写、引号嵌套),建议结合 strings.FieldsFunc() 预处理或引入专用分词库(如 golang.org/x/text/unicode/norm + 自定义逻辑);
  • 在正则中启用 (?i) 时,p{L} 仍保持大小写无关性,无需额外配置。

通过替换为 Unicode 感知的字符类,即可让 Go 正则真正“读懂”世界语言。

text=ZqhQzanResources