Slick one-liner 将像“1: 2, 3, 4, 5”这样的列表转换为“1.2, 1.3, 1.4, 1.5”

Dan*_*ury 7 awk shell-script text-processing

假设我有一个看起来像这样的文件:

23: a, b, c, d
24: b, d, f
25: c, g
Run Code Online (Sandbox Code Playgroud)

我想得到这样的输出:

23.a
23.b
23.c
23.d
24.b
24.d
24.f
25.c
25.g
Run Code Online (Sandbox Code Playgroud)

当然,将一些东西敲出来并不太难,但我想知道是否有使用 awk 之类的东西的光滑单线。

Sté*_*las 19

也许是这样的:

sed 's/: /./;s/\(\([^.]*\.\)[^,]*\), /\1\
\2/;P;D'
Run Code Online (Sandbox Code Playgroud)

那是两行(\<LF>可以\n用一些sed实现替换)。

D命令是实现一种方法,而循环sed。它删除了模式空间的第一行,只要模式空间中还有剩余的东西,剩下的就从头开始。所以上面的可以理解为:

do {
  - change ": " to "." so we start with "23.a, b, c"
  - change "23.x, y, z" to "23.x\n23.y, z"
  - print the first line ("23.x"): P
  - remove it
} while (pattern space is not empty)
Run Code Online (Sandbox Code Playgroud)

我们不需要第一个s命令成为循环的一部分,但为了避免这种情况,我们需要使用更详细的循环类型,例如使用标签 ( :) 和分支命令 ( b, t)。

  • 很好,但我们喜欢对代码所做的解释...... (3认同)

ter*_*don 10

这是一个 Perl 的:

 perl -nle '/(.+?):\s*(.+)/; print "$1.$_" for split(/[,\s]+/,$2);' foo.txt
Run Code Online (Sandbox Code Playgroud)

解释:

  • perl -nle: 这告诉 Perl 每次解析输入文件一行 ( -n),执行作为参数给定的脚本,并向每个打印的字符串 ( )-e添加一个新行\n( -l)。

  • /(.+?):\s*(.+)/: 匹配第一个字符,直到第一个冒号后跟 0 个或多个空格 ( :\s*),然后是该行的其余部分。括号是用于捕获模式的 Perl 语法,两个匹配项保存为$1and $2

  • split(/[,\s]*/,$2);:这将$2,和/或空格处拆分(上面匹配操作中的第二个匹配模式),创建一个匿名数组。

  • print "$1.$_" for split(): 遍历由上述拆分创建的匿名数组,将每个数组成员另存为$_并将其与$1(在第一步中捕获的第一个模式)和一个 dot 一起打印.


Dan*_*ury 10

没关系,我只记得 awk split 函数,这使得这非常简单。

awk -F ":" '{
  split($2, ps, ",");
  for (i in ps) {
    gsub(" ", "",ps[i]);
    print $1 "." ps[i];
  }
}'
Run Code Online (Sandbox Code Playgroud)

( gsub 正在剥离无关的空白。)

不过,感谢其他答案。


小智 5

这是一个红宝石:

ruby -ane '$F.drop(1).each{|f| puts $F.first.gsub(":",".")+f.chomp(",")}' <file.txt
Run Code Online (Sandbox Code Playgroud)

解释

  • 红宝石-ane:这告诉Ruby来a反对派线,一个分裂李n在时间e和execute参数为脚本。

  • 在自动拆分文件中$F是拆分结果的数组。

  • drop(1)跳过第一个字段(行号)并.each循环遍历以下字段。

  • gsub替换:chomp从字符串中删除尾随分隔符。