$和Perl的全局正则表达式修饰符

dra*_*n11 5 regex perl

我终于想出了如何将文本追加到文件中每行的末尾:

perl -pe 's/$/addthis/' myfile.txt
Run Code Online (Sandbox Code Playgroud)

但是,由于我正在尝试使用Perl进行频繁的正则表达式使用,我无法弄清楚为什么以下perl命令将文本'addthis'添加到每行的结尾和开头:

perl -pe 's/$/addthis/g' myfile.txt
Run Code Online (Sandbox Code Playgroud)

无论用什么修饰符用于正则表达式匹配,我都认为'$'匹配一行的结尾,但我想这是错的?

Jim*_*vis 10

简介: 对于您正在做的事情,请将/g其删除,使其仅换行符之前匹配.在/g告诉它的换行符之前的匹配,并在(之后的换行符)的字符串的结尾.

如果没有/m修饰符,$则会在换行符之前(如果它出现在字符串的末尾)或字符串的结尾处匹配.例如,使用"foo""foo\n",$之后匹配foo.有了"foo\nbar",不过,它会经过匹配bar的,因为嵌入式换行符是不是在字符串的结尾.

使用/g修饰符,您将获得所有$匹配的位置 - 所以

s/$/X/g;
Run Code Online (Sandbox Code Playgroud)

会像一条线一样"foo\n"把它变成"fooX\nX".

边栏:/m修改将允许$以匹配发生换行符之前的字符串的结束,使

s/$/X/mg;
Run Code Online (Sandbox Code Playgroud)

会转换"foo\nbar\n""fooX\nbarX\nX".


Dav*_* W. 5

正如吉姆戴维斯指出的那样,$匹配字符串的结尾或\n字符之前(带/m选项).(请参阅perlre Perldoc页面的正则表达式部分.使用修饰符可以继续匹配.g

多行Perl正则表达式(即,Perl正则表达式中包含新行字符,即使它只出现在行尾的一次)会导致大多数Perl程序员遇到问题处理的各种复杂情况.

  • 如果您一次读取一行文件,请始终chomp在使用该行进行任何操作之前使用.这可以在使用g限定符时解决您的问题.

  • 如果您正在阅读来自Windows的Linux/Mac上的文件,则可能会出现更多问题.在这种情况下,你将拥有\r\n角色.正如我最近在尝试调试程序时发现的那样,该\r字符不会被删除chomp.我现在确保我总是打开我的文本文件进行阅读

像这样:

open my $file_handle, "<:crlf", $file...
Run Code Online (Sandbox Code Playgroud)

这将自动替换\r\n字符,只要\n它实际上是Linux/Mac系统上的Windows文件.如果这是一个普通的Linux/Mac文本文件,它将什么都不做.其他明显的解决方案是不使用Windows(rim shot!).

当然,在你的情况下,首先使用chomp会做到以下几点:

$cat file
line one
line two
line three
line four
$ perl -pe 'chomp;s/$/addthis::/g`
line oneaddthis::line twoaddthis::line threeaddthis::line fouraddthis::
Run Code Online (Sandbox Code Playgroud)

chomp删除了\n,所以现在,当打印出来时,你看不到它.嗯...

$ perl -pe 'chomp;s/$/addthis/g;print "\n";
line oneaddthis
line twoaddthis
line threeaddthis
line fouraddthis
Run Code Online (Sandbox Code Playgroud)

这样可行!而且,你的一个班轮只是略微难以理解.


另一件事是采用Damian Conway在其Perl Best Practices一书的第12章中推荐的更现代的方法:

使用\A\z作为字符串边界锚点.

即使你不采用以前的使用/ m的做法,使用^和$的默认含义也是一个坏主意.当然,你知道在Perl正则表达式1中 ^和$实际意味着什么.但阅读或维护代码的人会知道吗?或者他们更有可能以前面描述的方式误解这些元字符?Perl提供的标记始终 - 并且明确地 - 表示"字符串的开头"和"字符串的结尾":\ A和\ z(大写字母A,但是小写字母z).它们的意思是"字符串的开始/结束",无论/ m是否有效.它们的意思是"字符串的开头/结尾",无论读者认为是什么和$均值.

如果您遵循Conaway的建议,并且这样做:

perl -pe 's/\z/addthis/mg' myfile.txt
Run Code Online (Sandbox Code Playgroud)

您会看到您的短语addthis仅添加到每行的末尾:

$cat file
line one
line two
line three
line four
$ perl -pe `s/\z/addthis/mg` myfile.txt
line one
addthisline two
addthisline three
addthisline four
addthis
Run Code Online (Sandbox Code Playgroud)

看看它有多好.这addthis被添加到每一行的最后!......就\n在那一行上的角色之后.

足够的乐趣和恢复工作.(等等,这是总统日.这是一个带薪假期.今天没有工作,当然除了我承诺在星期二早上做的所有事情).

希望这有助于您了解正则表达式有多么有趣,以及为什么这么多人决定学习Python.


1.知道Perl中的内容^$真正意义吗?呃,当然可以.我已经在Perl编程了几十年.是的,我知道这些东西.(自我注意:$显然并不代表我一直认为的意思.)