Go语言基于正则生成首字母缩写的特殊字符匹配问题
Go版本
go version go1.16.7 linux/amd64
问题描述
我正在完成生成首字母缩写的练习,选择用正则表达式实现。给出的测试用例如下:
input: "Ruby on Rails", expected: "ROR" input: "GNU Image Manipulation Program", expected: "GIMP" input: "Complementary metal-oxide semiconductor", expected: "CMOS" input: "Something - I made up from thin air", expected: "SIMUFTA" input: "Halley's Comet", expected: "HC" input: "The Road _Not_ Taken", expected: "TRNT"
当前编写的代码可通过大部分简单测试,提取单词首字母生成缩写,例如Portable Network Graphics -> PNG,代码如下:
代码实现
// Package acronym creates an acronym based on Capitalized Letters package acronym import ( "regexp" "strings" ) // Abbreviate: creates an acronym for a full form string func Abbreviate(s string) string { re := regexp.MustCompile(`\b[A-Za-z]`) abbreviation := strings.Join(re.FindAllString(s, -1), "") return strings.ToUpper(abbreviation) }
当前仅两个测试用例不通过:
=== RUN TestAcronym acronym_test.go:11: Acronym test [Halley's Comet], expected [HC], actual [HSC] acronym_test.go:11: Acronym test [The Road _Not_ Taken], expected [TRNT], actual [TRT] --- FAIL: TestAcronym (0.00s)
待解决问题
我不清楚如何调整正则,才能让Halley's Comet返回HC,同时匹配到The Road _Not_ Taken中的N。我保留小写字母[a-z]匹配是为了适配小写开头单词的测试用例,不想使用提前删除特殊字符的hack方案降低通用性,请问要怎么处理'、_这类字符,让缩写生成函数更鲁棒?
解决方案
问题原因
原正则使用的原生\b单词边界规则不符合需求:
- 原生单词边界的判定逻辑为「单词字符(a-z、A-Z、0-9、_)与非单词字符的交界」,
'属于非单词字符,因此Halley's中'和s的交界会被判定为单词边界,导致多匹配到s得到错误结果HSC - 下划线
_属于原生单词字符范畴,因此_Not_中_和N的交界不会被判定为单词边界,导致漏匹配N得到错误结果TRT
调整后代码
// Package acronym creates an acronym based on Capitalized Letters package acronym import ( "regexp" "strings" ) // Abbreviate: creates an acronym for a full form string func Abbreviate(s string) string { // 正则逻辑:匹配字符串开头/非字母+非单引号 后的第一个英文字母 re := regexp.MustCompile(`(?:^|[^a-zA-Z'])([a-zA-Z])`) matches := re.FindAllStringSubmatch(s, -1) var abbreviation strings.Builder for _, match := range matches { abbreviation.WriteString(match[1]) } return strings.ToUpper(abbreviation.String()) }
逻辑说明
- 用非捕获组
(?:^|[^a-zA-Z'])定义首字母的前置规则:要么是字符串开头,要么前一个字符既不是英文字母也不是单引号,保证单引号连接的内容不会被拆分为多个单词 - 用捕获组提取符合条件的英文字母,过滤掉前置的非字母字符
- 拼接所有捕获到的首字母后转大写,兼容小写开头的单词场景,无需额外预处理特殊字符
内容的提问来源于stack exchange,提问作者user4851126
相关产品推荐
相关产品推荐

