如何在这种情况下提取文件名?

时间:2012-05-31 19:33:36

标签: regex perl text-extraction

我的输入字符串如下所示:

1    warning: rg: W, MULT: file 'filename_a.h' was listed twice.
2    warning: rg: W, SCOP: scope redefined in '/proj/test/site_a/filename_b.c'.
3    warning: rg: W, ATTC: file /proj/test/site_b/filename_c.v is not resolved.
4    warning: rg: W, MULTH: property file filename_d.vu was listed outside.

它们有四种不同的味道,如上所列。我逐行从日志文件中读取这些内容。

对于指定路径的那个(第2,3行),我可以使用$file=~s#.*/##;提取文件名,似乎工作正常。有没有办法不使用不同类型的条件语句并提取文件名?我想只使用一个干净的正则表达式并提取文件名。在这种情况下,Perl的File::basename也不起作用。

我正在使用Perl。

3 个答案:

答案 0 :(得分:2)

您的问题需要更多限制。例如,将字符串表征为“路径”(或“文件名”)的好方法是什么?你可能会说,“嘿,当我看到一个点后面紧跟着字母和数字(但不是符号),并且在该点之前还有一堆字符,那么它可能是一个路径或文件名!”

\s+([^\s]+\.\w+)

但这并没有捕获所有路径,也没有没有扩展名的文件。所以我们可能会在交替上说“上面的,或者是一个至少有一个斜线的字符串。”

\s+([^\s]+\.\w+|[^\s]*\/[^\s]*)

(请注意,您可能不需要在上面的示例中转义斜杠,因为您似乎使用#作为分隔符。)

无论如何,我得到的是,您需要更严格地指定问题,这将自动为您带来满意的解决方案。当然,没有单独使用正则表达式的真正“正确”解决方案:您需要进行文件测试才能做到这一点。

要进一步了解此示例,您可能希望定义扩展列表:

\s+([^\s]+\.(?:c|h|cc|cpp)|[^\s]*\/[^\s]*)

或许,您可能想要更通用,但只允许最多4个字符的扩展名:

\s+([^\s]+\.\w{1,4}|[^\s]*\/[^\s]*)

也许你只考虑一个路径,如果它以斜杠开头,但你仍然希望其中至少有另一个斜杠:

\s+([^\s]+\.\w{1,4}|/[^\s]*\/[^\s]*)
祝你好运。

答案 1 :(得分:2)

你可以分两步完成:

  • 从每行提取路径
  • 从路径中获取基本名称

Example

#!/usr/bin/perl -n
use feature 'say';
use File::Basename;

#NOTE: assume that unquoted path has no spaces in it 
say basename($1.$2) if /(?:file|redefined in)\s+(?:'([^']+)'|(\S+))/;

输出

filename_a.h
filename_b.c
filename_c.v
filename_d.vu

答案 2 :(得分:0)

/ \ W *。\ W * / 这将匹配四个不同警告日志中表示的文件名。 \ w将匹配任何单词字符(字母,数字和下划线),因此此正则表达式查找任意数量的单词字符,后跟一个点后跟更多单词字符。 这是有效的,因为日志中唯一的其他点位于日志的末尾。