我正在调查一个正则表达式之谜。我很累,所以我可能会遗漏一些明显的东西——但我看不出有任何原因。
在下面的示例中,我使用 perl - 但我第一次在 VIM 中看到它,所以我猜测它与多个正则表达式引擎有关。
假设我们有这个文件:
$ cat data
1 =2 3 =4
5 =6 7 =8
然后我们可以删除'='前面的空格......
$ cat data | perl -ne 's,(.)\s+=(.),\1=\2,g; print;'
1=2 3=4
5=6 7=8
请注意,在每一行中,匹配的所有实例都被替换;我们使用了 /g 搜索修饰符,它不会在第一次替换时停止,而是继续替换直到行尾。
例如,'=2' 之前的空格和 '=4' 之前的空格都被删除了;在同一行。
为什么不使用更简单的结构,例如 's, =,=,g'?好吧,我们正在为更困难的场景做准备......其中赋值的右侧是带引号的字符串,可以是单引号或双引号:
$ cat data2
1 ="2" 3 ='4 ='
5 ='6' 7 ="8"
为了做同样的工作(删除等号前的空格),我们必须小心,因为字符串可能包含等号 - 所以我们标记我们看到的第一个引号,并通过反向引用查找它:
$ cat data2 | perl -ne 's,(.)\s+=(.)([^\2]*)\2,\1=\2\3\2,g; print;'
1="2" 3='4 ='
5='6' 7="8"
我们使用反向引用 \2 来搜索与我们第一次看到的引用不同的任何引用([^\2]*)。然后我们搜索原始报价本身 (\2)。如果找到,我们使用反向引用来引用替换目标中的匹配部分。
现在看看这个:
$ cat data3
posAndWidth ="40:5 =" height ="1"
posAndWidth ="-1:8 ='" textAlignment ="Right"
我们在这里想要的是删除每行中所有'=' 实例之前存在的最后一个空格字符。和以前一样,我们不能使用简单的 's, =",=",g',因为字符串本身可能包含等号。
所以我们遵循与上面相同的模式,并使用反向引用:
$ cat data3 | perl -ne "s,(\w+)(\s*) =(['\"])([^\3]*)\3,\1\2=\3\4\3,g; print;"
posAndWidth="40:5 =" height ="1"
posAndWidth="-1:8 ='" textAlignment ="Right"
它有效......但仅在第一场比赛中!'textAlignment' 后面的空格没有被删除,它上面的空格也没有被删除('height' 那个)。
基本上,似乎 /g 不再起作用了:在没有 /g 的情况下运行相同的替换命令会产生完全相同的输出:
$ cat data3 | perl -ne "s,(\w+)(\s*) =(['\"])([^\3]*)\3,\1\2=\3\4\3,; print;"
posAndWidth="40:5 =" height ="1"
posAndWidth="-1:8 ='" textAlignment ="Right"
似乎在这个正则表达式中, /g 被忽略了。任何想法为什么?