2013-02-20 55 views
1

我有一组特定的重复文本块。他们有一个动态文件名和一个动态消息。对于每个文件名我想提取消息。如何排除两个匹配之间的正则表达式文本?

Filename: dynamicFile.txt 
Property: some property to neglect 
Message: the message I want 
Time: dynamicTime 

我想提取部分消息后,这将是:the message I want

我有:以下将匹配文件名和时间之间的任何东西。

(?<=Filename: %myFileVar%)(?s)(.*)(?=Time:) 

%myFileVar%是动态的文件变量我将饲料与表达。

现在我需要找到一种方法来在文件名之后省略任何东西,直到消息部分。在这里,我将不得不省去:

Property: some property to neglect 
Message: 

这怎么能做到?

回答

2
use warnings; 
use strict; 

my $text; 
{ 
    local $/; 
    $text = <DATA>; 
} 

my $myFileVar = 'dynamicFile.txt'; 

if ($text =~ /Filename: \Q$myFileVar\E.*?Message: (.*?)\s*Time:/s) 
{ 
    print $1;  
} 

__DATA__ 
Filename: dynamicFile.txt 
Property: some property to neglect 
Message: the message I want 
Time: dynamicTime 

注意:这里假设Time:总是在消息行之后。如果不是这样,池上的解决方案提供了一种跳过其他线路的方法。

说明:

  • 您只需插入一个变量到你的模式,它会被插入。
  • 但是,如果变量包含任何特殊的正则表达式字符,则它们将被视为正则表达式字符。因此,你需要围绕变量\Q...\E,这使得一切都在字面上处理。如果你没有这样做,你的文件名中的点将匹配任何字符。
  • 您不需要使用lookaround来仅捕获部分字符串。取而代之的是使用一个捕获组 - 任何模式中的普通括号会自动放入变量$1,$2
  • 对于这样的简单情况,最好启用单线模式(s)作为模式后的开关。 (/s而不是(?s))。在模式中打开它是实验性的,只有在您需要将其应用于模式的一部分时才能使用。
  • .*?应该用来代替.*。否则,该模式将匹配文件中第一个Message:到最后一个Time:的所有内容。
+0

这将包括捕获中消息和时间之间的所有行。 – ikegami 2013-02-20 10:08:13

+0

@ikegami,感谢您指出'\ s *'问题。正如我理解这个问题,有一个固定格式的块,所以时间总是会在消息之后出现。 – 2013-02-20 10:14:24

+0

他之前的问题已经添加了一个字段。一些灵活性不会是一个坏主意, – ikegami 2013-02-20 10:16:10

1
/ 
^
    Filename: \s* \Q$myFileVar\E \n 
    (?: (?!Message:) [^\n]*\n)* 
    Message: \s* ([^\n]*) \n 
    (?: (?!Time:) [^\n]*\n)* 
    Time: 
/mx 

(?: [^\n]*\n)*跳过任何数量的行。

+0

'(?:[^ \ n] * \ n)*将在回溯到最后一条消息之前一直匹配文本的末尾。 – MikeM 2013-02-20 10:21:31

+0

我的意思是说,如果文本中有多个块,它可能会得到错误的信息。 – MikeM 2013-02-20 11:40:12

+0

@MikeM,的确,修正了。 – ikegami 2013-02-20 11:49:10

0

Perl可以做\K魔术

添加迟到的答案,因为我没有看到我最喜欢的解决方案。在Perl正则表达式中,\K告诉引擎放弃迄今为止与最终匹配相匹配的所有内容。所以,你也可以使用这个表达式:

(?sm)^Filename:.*?Message: \K[^\r\n]+ 

甚至:

(?m)^Message: \K[^\r\n]+ 

demo