【发布时间】:2013-03-09 21:31:53
【问题描述】:
我正在调查一个正则表达式之谜。我很累,所以我可能会失踪 一些显而易见的事情 - 但我看不出有任何原因。
在下面的例子中,我使用 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"
我们在这里想要的是删除存在的 last 空格字符 在所有每行中的“=”实例之前。像以前一样,我们不能使用 一个简单的 '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' 后面的空格没有被删除,也没有被删除 在它之上(“高度”)。
基本上,/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 被忽略了。 任何想法为什么?
【问题讨论】:
-
不是将第一个引号和最后一个引号之间的所有内容都视为带引号的字符串吗?
-
[^\3]* 部分不能在结束引号之外继续匹配,可以吗?
-
使用您的 perl cmd,我得到了不同的结果
posAndWidth="40:5="5和=之间的空格消失了。 -
从每一行中删除第一个条目时会发生什么?那么第二个匹配吗?如果是这样,你的锚地有问题。如果不是,那就是 RegEx 的问题。乍一看,我也看不出它们有什么缺陷。
-
获取this table 了解 Perl 反斜杠转义在各种上下文和版本中的含义。简短的故事是字符类中 1-3 位数字之前的反斜杠是八进制数,因此您的
\3是\cC或\x03或\x{0003}— 换句话说,它是一个 Control-C 时在字符类中使用。