4.20. 限制范围

未匹配的标注

4.20 限制范围

之前我们说:正则表达式尝试匹配最长可能的字符串,因此能造成一些意料不到的问题。比如看这个匹配括号内任意数量字符的正则表达式。

".*"

让我们看一下一个 troff 宏,有两个括号括起来的参数如下所示:

.Se "Appendix" "Full Program Listings"

要匹配第一个参数,我们可能需要如下正则表达式来描述这个模式:

\.Se ".*"

然而它最终匹配了一整行,因为在模式中的第二个引号匹配了这一行的最后一个引号。

➜  ch03 git:(daily) ✗ gres '\.Se ".*"' '00' sampleLine
00

如果你知道有多少个参数,你可以将它们一一指定。

\.Se ".*" ".*"

虽然这像你预期的那样工作,但每一行可能不会有同样数量的参数,这会造成遗漏,你只是想要第一个参数。

➜  ch03 git:(daily) ✗ gres '\.Se ".*" ".*"' '00' sampleLine
00

下面是一个不同的正则表达式,它匹配了两个引号之间最短的可能内容:

"[ˆ"]*"

它匹配了“一个双引号接着任意个不是双引号的字符,紧接着一个双引号”。

➜  ch03 git:(daily) ✗ gres '"[^"]*"' '00' sampleLine
.Se 00 "Full Program Listings"

现在让我们看看几行数字,它们用点字符(.)作为两列数字之间的指向符:

1........5
5........10
10.......20
100......200

匹配指向符的困难在于它们的数量是可变的。假如你匹配所有的指向符为一个tab。你可能写一个正则表达式去匹配行如下:

[0-9][0-9]*\.\.*[0-9][0-9]*

这个表达式可能会意外的匹配这一行:

see Section 2.3

为了限制匹配,你可以指定所有行共有的最小数量的点。

[0-9][0-9]*\.\{5,\}[0-9][0-9]*

这个表达式使用了 sed 的里面有的大括号{} 来匹配“一个数字接着至少五个点,再接着一个数字”。为了看清楚发生了什么,我们将展示替换指向符的点为连接符的一个 sed 命令。然而我们还没有学习 sed 的替换元字符—— \(\) 来保存正则表达式的一部分和用 \1\2 来重新调用保存部分的语法。因此这个命令可能看起来相当复杂(它确实是复杂)但是它完成了这个工作。

➜  ch03 git:(daily) ✗ sed "s/\([0-9][0-9]*\)\.\{5,\}\([0-9][0-9]*\)/\1-\2/" sample2
1-5
5-10
10-20
100-200

可以写类似的表达式来匹配在数据列之间的tab或前导的tab。你可以更改列的顺序也可以将替换为另一个分割符。你应该动手时自己实验一下。使用 sed 或 gres 来进行简单和复杂的替换。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 查看所有版本


暂无话题~