0

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

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#.*/##;并且似乎工作正常。有没有办法不对不同类型使用条件语句并提取文件名?我只想使用一个干净的正则表达式并提取文件名。PerlFile::basename在这种情况下也不起作用。

我正在使用 Perl。

4

3 回答 3

2

您可以分两步完成:

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

例子

#!/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
于 2012-05-31T20:43:24.767 回答
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]*)

祝你好运。

于 2012-05-31T20:14:07.950 回答
0

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

于 2012-05-31T20:29:53.307 回答