我从golang.org 网站阅读了示例代码。本质上,代码如下所示:
re := regexp.MustCompile("a(x*)b")
fmt.Println(re.ReplaceAllString("-ab-axxb-", "T"))
fmt.Println(re.ReplaceAllString("-ab-axxb-", "$1"))
fmt.Println(re.ReplaceAllString("-ab-axxb-", "$1W"))
fmt.Println(re.ReplaceAllString("-ab-axxb-", "${1}W"))
Run Code Online (Sandbox Code Playgroud)
输出是这样的:
-T-T-
--xx-
---
-W-xxW-
Run Code Online (Sandbox Code Playgroud)
我理解第一个输出,但我不理解其余三个。有人可以向我解释结果 2,3 和 4。谢谢。
最耐人寻味的是那条fmt.Println(re.ReplaceAllString("-ab-axxb-", "$1W"))线。文档说:
在 repl 内部,
$符号被解释为Expand
并展开说:
在模板中,变量由
$name或形式的子字符串表示${name},其中 name 是字母、数字和下划线的非空序列。 对超出范围或不匹配的索引或正则表达式中不存在的名称的引用将替换为空切片。在该
$name形式中,名称尽可能长:$1x相当于${1x}, not${1}x,并且,$10相当于${10}, not${1}0。
因此,在第三次替换中,$1W被视为${1W}并且由于该组未初始化,因此使用空字符串进行替换。
当我说“组未初始化”时,我的意思是说该组未在正则表达式模式中定义,因此,在匹配操作期间未填充该组。替换意味着获取所有匹配项,然后将它们替换为替换模式。反向引用($xx构造)是在匹配阶段填充的。模式中缺少该组,因此在匹配$1W期间未填充该组,并且在发生替换阶段时仅使用空字符串。
第二个和第四个替换很容易理解,并且已经在上面的答案中进行了描述。只需反向引用第一个捕获组捕获的$1字符(用一对未转义括号括起来的子模式),与示例 4 相同。
您可以将其视为消除替换模式歧义{}的一种方法。
现在,如果您需要使结果一致,请使用命名捕获 (?P<1W>....):
re := regexp.MustCompile("a(?P<1W>x*)b") // <= See here, pattern updated
fmt.Println(re.ReplaceAllString("-ab-axxb-", "T"))
fmt.Println(re.ReplaceAllString("-ab-axxb-", "$1"))
fmt.Println(re.ReplaceAllString("-ab-axxb-", "$1W"))
fmt.Println(re.ReplaceAllString("-ab-axxb-", "${1}W"))
Run Code Online (Sandbox Code Playgroud)
结果:
-T-T-
--xx-
--xx-
-W-xxW-
Run Code Online (Sandbox Code Playgroud)
第二行和第三行现在产生一致的输出,因为命名组1W也是第一组,并且$1编号反向引用指向使用命名捕获捕获的相同文本$1W。