我正在编写一个必须从文件中获取值的程序。在文件中,每一行表示一个实体。每个实体都有三个值。例如:
Value1 Value2 value3
我有一个正常的表达来匹配他们
m/(.*?) (.*?) (.*?)/m;
但似乎第三个值从未匹配过!匹配第三个值的唯一方法是在文件中添加另一个值,并在表达式中添加另一个“匹配括号”。但这并不能让我满意。
答案 0 :(得分:8)
在你想到用正则表达式做事之前,想一想没有它就能解决它。如果你想获得实体,更简单的方法是将它们分开。返回列表的元素将是您想要的。
@s = split /\s+/ , $line;
答案 1 :(得分:7)
让我们简化一下你的正则表达式的捕获,因为它不对发生的事情负责。因此你的正则表达式是这样的:
/.*? .*? .*?/
.*?
的含义是“匹配任何字符(换行符除外),尽可能少地匹配任何字符。”
在此上下文中,第一个.*?
将尝试匹配字符串中的零个字符,然后在下一个正则表达式元素(空格)上失败。它将再次尝试匹配字符串中的一个,两个......字符,并且当下一个字符是实际空格时将首先成功。
换句话说,事实上我们在.*?
组后面有一个空格,使其符合您的要求。否则它会很乐意停止匹配零字符。
这正是你的第三场比赛所发生的事情。由于正则表达式在那里结束,因此空匹配确实满足正则表达式组,并且是首选匹配。
正如其他答案所说,可能的解决方案包括:
split
(预期语义IMO的最佳转录).*
而不是.*?
)$
如果该行结束\S
)而不是任何字符(.
)。这适用于贪婪(\S*
)或不同意(\S*?
)匹配。答案 2 :(得分:5)
在$
的末尾添加regex
来解决此问题:
m/(.*?) (.*?) (.*?)$/m;
或者,您可以制作最后一部分greedy
:
m/(.*?) (.*?) (.*)/m;
答案 3 :(得分:5)
在这种情况下,您真的不想使用*
量词,并且您不希望让这些量词变得贪婪。正则表达式中的技巧是尽可能具体地描述模式。
您要匹配的行有:
一旦您描述了这种情况,就可以将其翻译成正则表达式。您可以从描述的字面翻译开始:
my @values = /(\S+) (\S+) (\S+)/;
由于您使用了\S
,因此捕获中的模式部分无法通过空格来匹配比您想要的更多,因为.*
可以。
你重复了部分模式,所以你可以压缩它。由于您只是捕获空白组,所以请改为全局匹配:
my @values = /(\S+)/g;
你也可以考虑反过来。您可以使用split:
丢弃空格,而不是捕获非空格 my @values = split /\s+/;