6

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

perl -pe 's/$/addthis/' myfile.txt

但是,当我尝试学习 Perl 以经常使用正则表达式时,我无法弄清楚为什么以下 perl 命令将文本“addthis”添加到每行的末尾和开头:

perl -pe 's/$/addthis/g' myfile.txt

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

4

3 回答 3

11

摘要: 对于您正在做的事情,请删除/g它,使其仅在换行符之前匹配。/g告诉它在换行符之前和字符串末尾(换行符之后)匹配。

如果没有/m修饰符,$将在换行符之前(如果它出现在字符串末尾)或字符串末尾匹配。例如,如果同时使用"foo"and "foo\n",则$将在 之后匹配foo"foo\nbar"但是,它会在 之后匹配,bar因为嵌入的换行符不在字符串的末尾。

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

s/$/X/g;

会取一条线"foo\n",然后把它变成"fooX\nX".

侧边栏: 修饰符/m将允许$匹配出现在字符串末尾之前的换行符,以便

s/$/X/mg;

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

于 2013-02-18T16:36:54.407 回答
5

正如吉姆戴维斯指出的那样,$匹配字符串的结尾或\n字符之前(带有/m选项)。(参见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::

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

$ perl -pe 'chomp;s/$/addthis/g;print "\n";
line oneaddthis
line twoaddthis
line threeaddthis
line fouraddthis

这样可行!而且,你的一个班轮只是有点难以理解。


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

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

即使您不采用以前始终使用 /m 的做法,使用具有默认含义的 ^ 和 $ 也是一个坏主意。当然,您知道 Perl 正则表达式1中 ^ 和 $ 的实际含义。但是那些阅读或维护您的代码的人会知道吗?还是他们更有可能以前面描述的方式误解这些元字符?Perl 提供的标记总是——并且明确地——表示“字符串的开头”和“字符串的结尾”:\A 和 \z(大写的 A,但小写的 z)。无论 /m 是否处于活动状态,它们都表示“字符串的开始/结束”。无论读者认为 ^ 和 $ 是什么意思,它们的意思是“字符串的开始/结束”。

如果您遵循康纳威的建议,并这样做:

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在那一行的字符之后。

玩够了,回去工作。(等等,今天是总统日。这是一个带薪假期。今天没有工作,当然除了我承诺在星期二早上之前完成的所有事情)。

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


1.知道Perl 中的含义^和真正含义吗?$嗯,是的,当然愿意。我已经用 Perl 编程了几十年。是的,我知道所有这些东西。(自我注意:$显然并不意味着我一直认为的意思。)

于 2013-02-18T17:32:45.377 回答
0

一种解决方法:

perl -pe 's/\n/addthis\n/' 

不需要g修饰符:正则表达式逐行处理。

于 2013-02-18T16:39:11.493 回答