什么是正则表达式替换“$ content = ~s / \ n-- \ n。*?$ // s”实际上在做什么?

时间:2013-08-07 19:56:34

标签: regex perl rt

我正在处理Request Tracker 4.0中的一些Perl代码,并且遇到了一个错误,即票据请求者的消息被切断。我是Perl的新手,我已经用正则表达式完成了一些工作,但即使阅读了很多,我也遇到了一些问题。

我已将问题缩小到这行代码:

$content =~ s/\n-- \n.*?$//s

我不完全明白它在做什么,想要更好的解释。

我了解s/ /与模式\n-- \n.*?$匹配,并将其替换为空。

我不明白.*?$的作用。这是我的基本理解:

  • .是除\ n
  • 之外的任何字符
  • *是前一个字符的0或更多倍
  • ?是前一个字符的0或1倍
  • $是字符串的结尾

然后,根据我的理解,最终s使.匹配新行

所以,粗略地说,我们正在替换以\n-- \n开头的任何文本 - 这行代码会导致一些可疑行为,如果有人能够解释这里发生了什么,我很乐意解决这个问题。

有人可以解释这条线路在做什么吗?它只是删除第一个之后的所有文本 \n-- \n或者还有更多内容吗?

冗长的部分/现实生活中的问题(您无需阅读本文即可回答此问题)

我的确切问题是它正在删除签名处的引用内容。

因此,如果来自客户的电子邮件A说:

  

订购ABCD的情况如何?    - 一些客户

工作人员的回复说(注意失去了客户的签名)

  

今天发货

     
    

ABCD订单发生了什么?

  

客户回复

  

我没有得到它,它没有发货!!!
   - 一些客户

     
    

今天发货

         
      

ABCD订单发生了什么?

    
  

当我们回复时,他们的信息将会切断 - 这将杀死所有上下文。

  

今天发货,追踪号码为12345

     
    

我没有得到它,它没有发货!

  

并导致更多工作解释它的顺序等等。

3 个答案:

答案 0 :(得分:8)

你几乎是正确的:它会删除从最后一次出现的“\ n-- \ n”到结尾的所有内容。这不会删除第一次出现的所有内容是由于非贪婪运算符? - 它告诉正则表达式引擎匹配前一个模式的最短可能形式(.*)。 / p>

这是做什么的:在电子邮件通信中,签名通常通过这种模式与消息体分开:一行由两个破折号和一个尾随空格组成。因此,正则表达式所做的是删除以签名分隔符开头的所有内容。

现在您的客户(手动或其电子邮件客户端)在签名分隔符后添加电子邮件的引用回复。这非常不寻常:引用的回复必须位于签名修饰符之前。我不知道有一个电子邮件客户端是故意这样做的,但是有很多程序只是从那里收到电子邮件(从引用的字符串问题到SMTP不符合,你可以犯下大量的错误) ,所以我不会惊讶地发现确实有这样的客户。

另一种可能性是,这是对客户的影响 - 就像在--之后签署自己的名字一样。但是,我怀疑这不是手动完成的,因为人们很少在两次破折后插入一个尾随空格,然后换行。

答案 1 :(得分:2)

?跟随量词(?*+{m,n})时,它会修改该量词的贪婪 [1 ] 。通常情况下,这些量词会尽可能匹配大多数字符,但使用?时,它们匹配的字符数最少。

say "Greedy:     ", "abc1234" =~ /\w(.*)\d/;
say "Non-greedy: ", "abc1234" =~ /\w(.*?)\d/;

输出:

bc123
bc

由于有两个地方$可以匹配(在尾随换行符之前或在字符串末尾),因此具有以下效果:

$_ = "abc\n-- \ndef\n";
say "Greedy:     <<" . s/\n-- \n.*$//sr  . ">>";
say "Non-greedy: <<" . s/\n-- \n.*?$//sr . ">>";

输出:

Greedy:     <<abc>>
Non-greedy: <<abc
>>

确保不会删除终止最后一行的换行符。以下是更直接的等价物:

s/\n-- \n.*/\n/s

s/(?<=\n)-- \n.*//s   # Slow

s/\n\K-- \n.*//s      # Requires 5.10

请注意,它将从第一个--开始删除。

$ perl -E'say "abc\n-- \ndef\n-- \nghi\n" =~ s/\n-- \n.*?$//sr'
abc

如果您想从最后一个开始删除,则必须将.*替换为保证不匹配--的内容。

$ perl -E'say "abc\n-- \ndef\n-- \nghi\n" =~ s/\n-- \n(?:(?!-- \n).)*?$//sr'
abc
-- 
def

注意:

  1. 如果它遵循另一个量词修饰符(例如/.*+?/),它也具有相同的含义。

答案 2 :(得分:1)

有一个很好的CPAN模块可以帮助您理解未来的正则表达式:YAPE::Regex::Explain

您可以在此处找到它的在线版本:http://rick.measham.id.au/paste/explain.pl

通过网站运行正则表达式会返回以下内容:

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  \n                       '\n' (newline)
--------------------------------------------------------------------------------
  --                       '-- '
--------------------------------------------------------------------------------
  \n                       '\n' (newline)
--------------------------------------------------------------------------------
  .*?                      any character except \n (0 or more times
                           (matching the least amount possible))
--------------------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string

根据文档,“Perl 5.6版之后不再支持正则表达式语法,特别是在5.10中添加的任何构造”,但在实践中你应该仍然可以使用它来帮助理解你遇到的大多数正则表达式