返回介绍

4.3 捕获分组和后向引用

发布于 2024-01-20 21:40:46 字数 3301 浏览 0 评论 0 收藏 0

当一个模式的全部或者部分内容由一对括号分组时,它就对内容进行捕获并临时存储于内存中。可以通过后向引用重用捕获的内容,形式为:

\1

$1

这里\1或$1引用的是第一个捕获的分组,而\2或$2引用第二个捕获的分组,以此类推。sed只接受\1这种形式,而Perl则两种都接受。

最开始sed支持范围从\1到\9的后向引用,但现在已经没有这样的限制了。

下面再展示一下后向引用的使用方法。我们将使用它来重新排序诗文中的一行词,在此先跟作者柯勒律治道个歉。点击RegExr的Repalce标签,在顶部的文本框中输入下面的模式:

(It is) (an ancyent Marinere)

向下滚动主文本框(第三个文本区)直到你可以看到被标亮的那一行,然后在第二个文本框中,输入:

$2 $1

就可以看到在最下面的文本框中那一行被重新排列为:

an ancyent Marinere It is,

结果参见图4-2。

图4-2 用$1$2进行后向引用

要用sed得到相同结果,可以这样做:

sed -En 's/(It is) (an ancyent Marinere)/\2 \1/p' rime.txt

输出为:

an ancyent Marinere It is,

和RegExr中一样。为了帮助你理解每个细节,下面我们来分析一下这个sed命令。

· -E选项仍然是调用ERE(扩展的正则表达式),因此,括号可以直接当成字面值来使用了。

· -n选项覆盖打印每一行的默认设置。

· 替换命令搜索与文本“It is an ancyent Marinere,”匹配的内容,再将其捕获放入两个分组中。

· 替换命令还将捕获的文本重排为先是后向引用\2的内容再是\1的内容,再将匹配的文本替换为重排后的内容并输出。

· 替换命令结尾处的p表示要打印该行。

Perl中类似的命令会做相同的事:

perl -ne 'print if s/(It is) (an ancyent Marinere)/\2 \1/' rime.txt

注意该命令使用了\1风格的语法。当然,你也可以使用$1语法:

perl -ne 'print if s/(It is) (an ancyent Marinere)/$2 $1/' rime.txt

我喜欢Perl允许不必在循环中跳转就能打印指定行的方式。

但关于输出,还有一点要注意的是:

an ancyent Marinere It is,

在转换过程中某些单词首字母的大小写被打乱了。Perl可以使用\u和\l来修正这个问题,就是这样:

perl -ne 'print if s/(It is) (an ancyent Marinere)/\u$2 \l$1/' rime.txt

现在结果看起来好多了:

An ancyent Marinere it is,

接下来解释一下原因。

· \l语法并不匹配任何字符,而是会将紧接其后的字母变为小写。

· \u语法将紧接其后的字母变为大写。

· \U指令(未展示)将紧接其后的文本字符串全部变为大写。

· \L指令(未展示)将紧接其后的文本字符串全部变为小写。

这些指令在文本中出现其他指令(比如\l或\E,作为文字使用的字符串的结尾)之前都是起作用的。请自己动手试试这些指令。

命名分组

命名分组(named group)就是有名字的分组。这样,就可以通过名字(而不是数字)来引用分组。下面展示一下Perl语言中如何使用命名分组:

perl -ne 'print if s/(?<one>It is) (?<two>an ancyent Marinere)/\u$+{two}\l$+{one}/' rime.txt

我们来看看这个命令:

· 在括号内添加?<one>和?<two>将分组分别命名为one和two;

· $+{one}引用名为one的分组,而$+{two}则引用名为two的分组。

如果在一个模式中有分组被命名,那么你还可以重用该命名分组。解释一下这句话的意思,假设你要查找含有连续六个0的字符串:

000000

这个例子很浅显,但可以说明其工作原理。用这一模式对连续三个0的分组命名(其中z是分组名,可以任意取):

(?<z>0{3})

然后你可以再使用该分组,就像这样:

(?<z>0{3})\k<z>

或者:

(?<z>0{3})\k'z'

或者:

(?<z>0{3})\g{z}

请在RegExr中尝试一下看看结果。这些示例应该都能用。表4-3列出了命名分组可能使用的各种语法。

表4-3 命名分组的语法

语法

描述

(?<name>…)

命名分组

(?name…)

另一种命名分组的方式

(?P<name>…)

Python中的命名分组

\k<name>

在Perl中引用分组名

\k'name'

在Perl中引用分组名

\g{name}

在Perl中引用分组名

\k{name}

在.NET中中引用分组名

(?P=name)

在Python中中引用分组名

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文