perl -pe 's/$/addthis/' myfile.txt
然而,由于我想学习Perl以便频繁使用正则表达式,我无法理解为什么以下Perl命令会在每行的开头和结尾添加文本“addthis”:
perl -pe 's/$/addthis/g' myfile.txt
我认为'$'符号无论在正则匹配中使用什么修饰符都表示匹配行尾,但我猜想这个理解是错误的?
摘要: 对于你正在做的事情,去掉/g
,这样它只匹配换行符前的内容。 /g
告诉它在换行符前和字符串结尾(换行符后)都要匹配。
没有/m
修饰符,$
将匹配换行符前(如果出现在字符串末尾)或字符串末尾之前的位置。例如,在"foo"
和"foo\n"
中,$
将在foo
之后匹配。但是,在"foo\nbar"
中,它将在bar
之后匹配,因为嵌入的换行符不在字符串末尾。
使用/g
修饰符,您将获取所有$
将匹配的位置 -- 因此
s/$/X/g;
会将类似于"foo\n"
的一行转换为"fooX\nX"
。
侧边栏:
/m
修饰符将允许$
匹配出现在字符串末尾之前的换行符。
s/$/X/mg;
将"foo\nbar\n"
转换为"fooX\nbarX\nX"
。
正如吉姆·戴维斯指出的那样,$
匹配字符串的末尾或者在/m
选项下匹配\n
字符之前。(请参见正则表达式部分和perlre Perldoc页面。使用g
修饰符可以使其继续匹配。)
多行Perl正则表达式(即,即使只在行末出现一次,也包含换行符的Perl正则表达式)会导致各种复杂问题,大多数Perl程序员都难以处理。
如果您逐行读取文件,请在操作该行之前始终使用 chomp
。这将解决您使用 g
限定符时遇到的问题。
如果您在 Linux/Mac 上读取来自 Windows 的文件,则可能会出现其他问题。在这种情况下,您将同时拥有 \r
和 \n
字符。最近我尝试调试程序时发现,\r
字符不会被 chomp
移除。因此,我现在总是确保以文本模式打开文件进行读取。
像这样:
open my $file_handle, "<:crlf", $file...
如果在Linux / Mac系统上使用的是Windows文件,则此功能将自动将\r\n
字符替换为\n
。 如果这是一个常规的Linux / Mac文本文件,则它将不起作用。 另一个明显的解决方案是不使用Windows(即使是个玩笑也可以!)。
当然,在您的情况下,先使用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::
$ perl -pe 'chomp;s/$/addthis/g;print "\n";
line oneaddthis
line twoaddthis
line threeaddthis
line fouraddthis
使用
\A
和\z
作为字符串边界锚点。即使您不采用始终使用 /m 的先前做法,使用具有默认含义的 ^ 和 $ 是一个坏主意。当然,您知道在 Perl 正则表达式中 ^ 和 $ 实际上意味着什么。但是阅读或维护代码的人会知道吗?还是他们更可能以前述方式错误地解释这些元字符? Perl 提供了标记,它们始终且明确地表示“字符串的开头”和“字符串的结尾”:\A 和 \z(大写 A,但小写 z)。无论 /m 是否激活,它们都表示“字符串的开头/结尾”。无论读者认为 ^ 和 $ 意味着什么,它们都表示“字符串的开头/结尾”。
如果您遵循 Conaway 的建议,并执行以下操作:
perl -pe 's/\z/addthis/mg' myfile.txt
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
addthis
被添加到每行的末尾!...紧接着该行的\n
字符后面。1. 了解在Perl中^
和$
的真正含义吗?嗯,是的,当然我知道。我已经用Perl编程几十年了。是的,我知道所有这些。 (自己注意:$
显然不是我一直以为的意思。)
perl -pe 's/\n/addthis\n/'
无需 g
修饰符:正则表达式逐行处理。
$
的文档吗? - ysth