【问题标题】:$ and Perl's global regular expression modifier$ 和 Perl 的全局正则表达式修饰符
【发布时间】:2013-02-18 16:33:10
【问题描述】:

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

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

但是,由于我正在尝试学习 Perl 以经常使用正则表达式,我无法弄清楚为什么以下 perl 命令会在末尾添加文本“addthis”并开始每行:

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

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

【问题讨论】:

  • 您是否阅读了$ 的文档?

标签: regex perl


【解决方案1】:

总结:对于你正在做的事情,删除/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"

【讨论】:

    【解决方案2】:

    正如Jim Davis 指出的那样,$ 匹配字符串的结尾或\n 字符之前(使用/m 选项)。 (参见perlre Perldoc 页面的Regular Expressions 部分。使用g 修饰符允许它继续匹配。

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

    • 如果您一次读取一行文件,请始终使用chomp,然后再对该行执行ANYTHING。使用 g 限定符时,这将解决您的问题。

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

    像这样:

    open my $file_handle, "<:crlf", $file...
    

    如果这实际上是 Linux/Mac 系统上的 Windows 文件,这将自动将 \r\n 字符替换为 \n。如果这是一个普通的 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::
    

    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 编程了几十年。是的,我知道所有这些东西。 (自我注意:$ 显然不是我一直认为的意思。)

    【讨论】:

    • 感谢您提供的信息丰富且有趣的回答!我以为我知道'$'是什么意思...这只年轻的蚱蜢有很多东西要学:)
    【解决方案3】:

    解决方法:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-22
      • 1970-01-01
      • 2012-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多