perl oneliner 在同一打印语句中打印数组和其他匹配项

mon*_*onk 3 regex perl

我有一组包含示例数据的文件,如下所示,我需要转换数据以将所有对象文件(以下)放在-o第一列中,将链接库(以下)-l放在第二列中。这个格式在整个make输出中是一致的。

hello there -o one two three four -labc -lfoo -lbar
something useless -o abc doo zoo  -lkoo -lfoo -lmoo
Run Code Online (Sandbox Code Playgroud)

我正在尝试将其解析为更简单的格式以进行进一步处理:

one two three four, abc foo bar
abc doo zoo, koo foo moo
Run Code Online (Sandbox Code Playgroud)

我正在尝试这个,显然这不是我想要得到的:

perl  -ne '/-o(.*?)-/m; @libs = /-l([^ ]+)/gs; printf "%s %s\n", $1 , join(", ", @libs);' inputfile
bar
 abc, foo, bar

moo
 koo, foo, moo
Run Code Online (Sandbox Code Playgroud)

在这里,我尝试将所有对象存储到数组中$1并将所有库存储到@libs数组中。只有库被正确打印,但对象不正确,有人可以帮助修复它吗?我单独验证了它$1是否具有正确的值。

perl  -wne '/-o(.*?)-/m;  printf "%s %s\n", $1, " "' inputfile
 one two three four
 abc doo zoo
Run Code Online (Sandbox Code Playgroud)

同样,当我单独打印第二部分(库)时,它也有效。

perl  -ne '@libs = /-l([^ ]+)/gs; printf "%s\n",  join(", ", @libs);' x
abc, foo, bar

koo, foo, moo
Run Code Online (Sandbox Code Playgroud)

所以,当我将两者结合在一起时,它只会变得混乱。

zdi*_*dim 5

perl -wnlE'\n    ($o, @l) = /-(?:o|l) \\s* ([^-]+) /gx;\n    s/\\s+$// for $o, @l;            \n    say join ", ", $o, "@l"\n' file\n
Run Code Online (Sandbox Code Playgroud)\n

file给定的两行上打印

\n
one two three four, abc foo bar\nabc doo zoo, koo foo moo\n
Run Code Online (Sandbox Code Playgroud)\n

为了使其按预期工作,至关重要的是首先有一个-o选项,然后是后续-l选项(可能有多个),以便以-(o|l)正确的顺序捕获并($o, @l)正确存储。\xe2\x80\xa0

\n

由于可以在 后面列出多个文件-o,并且文件之间有空格,因此我们必须在模式中允许空格,这样也会捕获尾随的文件;因此尾随空格清理是必要的。

\n

(我希望通过调整模式,应该能够纠正这一问题,以便不需要捕获后清理,但我现在看不到它。)

\n
\n

\xe2\x80\xa0这个格式已经在评论中确认过了,但是如果有多个-o条目或顺序不同,那么最简单的方法可能是将其分成两个正则表达式

\n
# Capture all `-o` entries, then all `-l` entries (order doesn't matter)\n@o = /-o\\s+([^-]+)/g; @l = /-l\\s*([^-]+)/g;  \n
Run Code Online (Sandbox Code Playgroud)\n

或者,也许对于库来说,宁愿使用

\n
@l = /-l(\\S+)/g;\n
Run Code Online (Sandbox Code Playgroud)\n

然后将它们全部打印为

\n
say join ", ", "@o", "@l";\n
Run Code Online (Sandbox Code Playgroud)\n
\n

对问题中代码的评论,除了一个障碍之外,实际上是正确的

\n

为什么它不起作用:第二个正则表达式填充了自己的捕获变量,因此$1第一个正则表达式被覆盖。解决此问题的一个简单方法是在第一个正则表达式中分配捕获,就像在第二个正则表达式中所做的那样($o) = /-o(.*?)-/(或如此),然后使用它 ( $o)。需要施加列表()上下文$o,以便返回捕获,而不仅仅是成功/失败(1/'' )

\n

其他一些注意事项

\n
    \n
  • 不需要/m也不需要/s,那些用于多行字符串

    \n
  • \n
  • [^ ]可以写成\\S(非空格:),我认为这样更清晰。所以/-l(\\S+)/g

    \n
  • \n
  • printf当我们需要格式化打印时,它非常强大和有用。在这里你不这样做,所以没有理由这样做,虽然它慢得多并且容易出错;可以做print join(...), "\\n";

    \n

    或者使用say,enabled by-E来代替-e。由于-E启用了所有其他功能,并且可能无法面向未来,因此最好CORE::say与 一起使用-e。在你会做的程序中use feature 'say';在你一开始

    \n
  • \n
\n

  • @monk在帖子末尾添加了代码讨论(答案),删除了评论...稍后可能会编辑更多(我永远不会做对!)但不会打扰你,除非有一些实质性的东西 (2认同)