《正则表达式经典实例(第2版)》——2.5 匹配文本行起始和或文本行结尾

本节书摘来自异步社区《正则表达式经典实例(第2版)》一书中的第2章,第2.5节,作者: 【美】Jan Goyvaerts , Steven Levithan著,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.5 匹配文本行起始和或文本行结尾

问题描述
分别创建4个正则表达式。匹配单词alpha,仅限于它出现在目标文本最开始的时候。匹配单词omega,仅限于它出现在目标文本结尾处的时候。匹配单词begin,仅限于它出现在文本行开始处的时候。匹配单词end,仅限于它出现在文本行结尾的时候。

解决方案
目标文本的开始

^alpha
正则选项:无(“^和$匹配换行处”选项必须关掉)
正则流派:.NET、Java、JavaScript、PCRE、Perl、Python
\Aalpha
正则选项:无
正则流派:.NET、Java、PCRE、Perl、Python、Ruby

目标文本的结尾

omega$
正则选项:无(“^和$匹配换行处”选项必须关掉)
正则流派:.NET、Java、JavaScript、PCRE、Perl、Python
omega\Z
正则选项:无
正则流派:.NET、Java、PCRE、Perl、Python、Ruby

行开始

^begin
正则选项:^和$匹配换行处
正则流派:.NET、Java、JavaScript、PCRE、Perl、Python、Ruby

行结尾

end$
正则选项:^和$匹配换行处
正则流派:.NET、Java、JavaScript、PCRE、Perl、Python、Ruby

讨论
定位符和行
正则表达式记号‹^›、‹$›、‹A›、‹Z›和‹z›被称作是定位符(anchor)。它们并不匹配任意字符。事实上,它们匹配的是特定的位置,也就是说把正则表达式瞄准这些位置来进行匹配。

行指的是位于目标文本的开始和第一个换行符、在两个换行符之间或者在最后一个换行符和目标文本结尾之间的那部分目标文本。如果在目标文本中不包含换行符的话,则整体目标文本就会被认为是一行。因此,下面的文本包含有4行,分别是one、two、一个空串和four。

one
two
four

这个文本可以在程序中采用如下的表示:oneLFtwoLF LFfour。

目标文本的起始
定位符‹A›总是会匹配目标文本的最开始处,也就是在第一个字符的前面。这也是它会匹配的唯一位置。可以把‹A›放到你的正则表达式的开始处,这样就可以检查目标文本是否是由你想要匹配的文本来开头的。注意这里的“A”必须是大写的。

JavaScript不支持‹A›。

定位符‹^›与‹A›是等价的,前提是不能打开“^ 和$匹配换行处”这个选项。对于除了Ruby之外的所有其他正则流派来说,该选项都是默认关闭的。但是要记住在Ruby中并没有提供可以关掉这个选项的方法。

除非你使用的是JavaScript,否则推荐总是使用‹A›,而不是‹^›。‹A›的含义始终保持不变,因此可以避免由于正则选项设置而造成的混淆或错误。

目标文本的结尾
定位符‹Z›和‹z›总是会匹配目标文本的结尾处,也就是说在最后一个字符之后。把‹Z›或‹z›放到正则表达式的结尾处,就可以测试是否目标文本会以你想要匹配的文本来作为结束。

.NET、Java、PCRE、Perl和Ruby同时支持‹Z›和‹z›。Python只支持‹Z›。JavaScript则根本不提供对‹Z›或‹z›的支持。

‹Z›和‹z›的唯一区别是当目标文本的最后一个字符是换行符的时候。在这种情形下,‹Z›可以匹配目标文本的最结尾处,也就是在最后的换行符之后的位置,同时也可以匹配紧跟在这个换行符之前的位置。这样做的好处是,你可以放心地搜索‹omegaZ›,而不必担心在你的目标文本的最后是不是会存在一个多余的换行符。当逐行读入一个文件的时候,有些工具会包含行末的换行符,而有些工具则不然;‹omegaZ›会把这种区别隐藏起来。‹z›则只会匹配目标文本的最末尾处,因此如果存在一个多余换行符的话,它就无法匹配。

定位符‹$›与‹Z›是等价的,前提是不要打开“^和$匹配换行处”这个选项。对于除了Ruby之外的所有其他正则流派来说,该选项都是默认关闭的。而且在Ruby中并没有提供可以关掉这个选项的方法。正像‹Z›一样,‹$›也会匹配目标文本的最末尾处,以及(如果存在的话)在最后一个换行符之前的位置。

为了帮助你更好地理解这里的细微差别,我们来看一个Perl中的例子。假设$/(当前记录分隔符)被设置为缺省的n,那么下面的Perl语句会从终端(标准输入)读入一行:

$line = <>;
Perl会在变量$line的内容中保留换行符。因此,采用像‹end●of●input.z›这样的表达式就无法匹配该变量。而如果使用‹end●of●input.Z›和‹end●of●input.$›则都可以匹配,因为它们会忽略后面多余的换行。

为了方便起见,Perl程序员通常会使用下面的命令来去掉换行符:

chomp $line;
在执行了上述操作之后,上面所给的3种定位符都会匹配。(严格来说,chomp会从当前字符串中抽掉记录的分隔字符。)

除非你使用的是JavaScript,否则推荐你总是使用‹Z›,而不是‹$›。‹Z›的含义始终保持不变,因此可以避免由于正则选项设置而造成的混淆或错误。

文本行开始
默认情况下,‹^›只会匹配目标文本的开始处,就像‹A›一样。只有在Ruby中,‹^›才会总是匹配一行的开始位置。所有其他流派都要求打开一个选项来使得^和$这两个符号可以匹配换行处。这个选项通常被称作是“多行”(multiline)模式。

千万别把这个模式同“单行”模式搞混,因为单行模式最好应该还是被称作是“点号匹配换行符”模式。“多行”模式只会影响到^和$这两个符号,而“单行”模式则只会影响到点号(如实例2.4所示)。你完全可以同时打开“单行”和“多行”模式。在默认情况下,这两个选项都是关闭的。

在设置了正确的选项之后,‹^›就可以匹配目标文本中每行的开始。严格来讲,它匹配文件中第一个字符之前的位置,以及在目标文本中每个换行符之后的位置。使用‹n^›是多余的,因为‹^›始终会匹配‹n›之后的位置。

文本行结束
默认情况下,‹$›只会匹配目标文本的结尾处或者是最后一个换行之前的位置,就像‹Z›一样。只有在Ruby中,‹$›才会总是匹配一行的结尾处。所有其他流派都要求你打开“多行”模式来使得^和$这两个符号可以匹配换行处。

在设置了正确的选项之后,‹$›会匹配目标文本中每行的结束。(当然,它同样会匹配目标文本中的最后一个字符之后的位置,因为这个位置也总是一行的结束。)使用‹$n›是多余的,因为‹$›总是会匹配‹n›之前的位置。

长度为0的匹配
对于一个正则表达式来说,它完全可以只包含一个或者多个定位符。这样一个正则表达式会在定位符能够匹配的每个位置查找一个长度为0的匹配。如果把多个定位符放在一起的话,只有当所有的定位符都在同一个位置匹配的时候,该正则式才会匹配成功。

可以在查找和替换的功能中使用这样的正则表达式。可以通过替换‹A›或‹Z›来在整体目标文本之前或者之后添加一些内容。也可以通过在“^和$匹配换行处”的模式下,替换‹^›或‹$›,在目标文本的每行之前或者之后添加一些内容。

把两个定位符组合起来则可以检查空行或者缺失的输入。‹AZ›会匹配空串,以及包含单个换行符的字符串。‹Az›则只能匹配空串。在“^和$匹配换行处”的模式下,‹^$›会匹配目标文本中的每个空行。

变体

(?m)^begin
正则选项:无
正则流派:.NET、Java、XRegExp、PCRE、Perl、Python
(?m)end$
正则选项:无
正则流派:.NET、Java、XRegExp、PCRE、Perl、Python

如果不能在正则表达式之外打开“^和$匹配换行处”的模式,也可以在正则表达式之前使用一个模式修饰符来达到相同的效果。在实例2.1中的“不区分大小写的匹配”一节中,我们已经讲解了模式修饰符的概念,并且了解了JavaScript并不对此提供支持。

在.NET、Java、XRegExp、PCRE、Perl和Python中,‹(?m)›是“^和$匹配换行处”模式的模式修饰符。其中的m指的是“多行”(multiline)模式,这个是在Perl中引入的用来描述“^和$匹配换行处”模式的名称,实在很容易让人感到混淆。

如前所述,这个术语实在是太容易让人弄混了,以致Ruby正则引擎的开发者都无法正确地遵循这种记法。在Ruby中使用‹(?m)›来打开“点号匹配换行符”模式。因此Ruby中的‹(?m)›与脱字符和美元符号都不存在任何关系。在Ruby中,‹^›和‹$›总是会匹配每一行的开始和结束。

除了令人遗憾的字母使用混淆之外,Ruby选择使用‹^›和‹$›只匹配每行是非常正确的。除非你使用的是JavaScript,我们推荐你在自己的正则表达式中都采用这种方式。

在Jan Goyvaerts设计EditPad Pro和PowerGREP的时候,他遵循了相同的想法。在这些工具中找不到关于“^和$匹配换行处”的复选框,虽然其中有个复选框的说明是“点号匹配新行”(dot matches newlines.)。除非在正则表达式之前添加了‹(?-m)›,否则就不得不使用‹A›和‹Z›来定位文件的开始和结束。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值