巧妙地将“1: 2, 3, 4, 5”等列表转换为“1.2, 1.3, 1.4, 1.5”

巧妙地将“1: 2, 3, 4, 5”等列表转换为“1.2, 1.3, 1.4, 1.5”

假设我有一个如下所示的文件:

23: a, b, c, d
24: b, d, f
25: c, g

我想得到这样的输出:

23.a
23.b
23.c
23.d
24.b
24.d
24.f
25.c
25.g

当然,仅仅敲出一些东西并不太难,但我想知道是否有一个使用 awk 之类的东西的巧妙的单行代码。

答案1

也许是这样的:

sed 's/: /./;s/\(\([^.]*\.\)[^,]*\), /\1\
\2/;P;D'

这是两行(可以用​​某些实现\<LF>替换)。\nsed

D命令是一种实现方式while 循环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)

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

答案2

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

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

(gsub 正在去除无关的空白。)

不过还是谢谢其他人的回答。

答案3

这是一个 Perl 的:

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

解释:

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

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

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

  • print "$1.$_" for split():迭代通过上面的分割创建的匿名数组,将每个数组成员保存为$_并将其与$1(第一步中捕获的第一个模式)和点一起打印.

答案4

我认为 awk 单行代码比其他 awk 解决方案更优雅:

awk -F'[:, ]+' '{for(i=2;i<=NF;i++)printf $1"."$i"\n"}' file.in

它利用了 awk 字段分隔符是正则表达式这一事实。

相关内容