【问题标题】:divide each line in equal part将每一行分成相等的部分
【发布时间】:2012-09-27 16:30:16
【问题描述】:

如果有人可以建议我使用命令(sed 或 AWK 单行命令)将文件的每一行分成相等的部分,我会很高兴。例如将每一行分成 4 部分。

输入:

ATGCATHLMNPHLNTPLML

输出:

ATGCA THLMN PHLNT PLML

【问题讨论】:

  • 您可以使用awkFIELDWIDTHS功能,例如:awk 'BEGIN { FIELDWIDTHS="5 5 5 5" } { for(i=1; i<NF; i++) printf("%s ", $i); print $NF }'
  • 欢迎来到 Stack Overflow!我们鼓励您research your questions。如果您有 tried something already,请将其添加到问题中 - 如果没有,请先研究并尝试您的问题,然后再回来。

标签: sed awk


【解决方案1】:

这应该使用 GNU sed 工作:

sed -r 's/(.{4})/\1 /g'
  • 使用扩展正则表达式需要-r
  • .{4} 每四个字符捕获一次
  • \1 指的是被捕获的组,被括号( ) 包围,并在该组后面添加一个空格
  • g 确保在每一行上尽可能多地进行替换

一个测试;这是我终端中的输入和输出:

$ echo "ATGCATHLMNPHLNTPLML" | sed -r 's/(.{4})/\1 /g'
ATGC ATHL MNPH LNTP LML

【讨论】:

  • \1 也可以在普通 sed 中使用,(){} 需要 -r(没有它,您必须使用 \(\)\{\})。跨度>
【解决方案2】:

我怀疑 awk 不是最好的工具,但是:

gawk --posix '{ l = sprintf( "%d", 1 + (length()-1)/4);
    gsub( ".{"l"}", "& " ) } 1' input-file

如果你有一个 posix 兼容的 awk,你可以省略 --posix,但 --posix 对于 gnu awk 是必需的,因为这似乎是最常用的实现,所以我给出了 gawk 的解决方案。

【讨论】:

    【解决方案3】:

    这可能对你有用(GNU sed):

    sed 'h;s/./X/g;s/^\(.*\)\1\1\1/\1 \1 \1 \1/;G;s/\n/&&/;:a;/^\n/bb;/^ /s/ \(.*\n.*\)\n\(.\)/\1 \n\2/;ta;s/^.\(.*\n.*\)\n\(.\)/\1\2\n/;ta;:b;s/\n//g' file
    

    解释:

    • h将模式空间(PS)复制到保持空间(HS)
    • s/./X/g 将 HS 中的每个字符替换为相同的非空格字符(在本例中为 X
    • s/^\(.*\)\1\1\1/\1 \1 \1 \1/将行分成4部分(空格分隔)
    • G 将换行符后跟 HS 的内容添加到 PS
    • s/\n/&&/ 将换行符加倍(稍后用作标记)
    • :a 引入循环命名空间
    • /^\n/bb 如果我们到达换行符,我们就完成并分支到 b 命名空间
    • /^ /s/ \(.*\n.*\)\n\(.\)/\1 \n\2/;ta; 如果第一个字符是空格,则此时在实行中添加一个空格并重复
    • s/^.\(.*\n.*\)\n\(.\)/\1\2\n/;ta 任何其他角色都会碰到并重复
    • :b;s/\n//g 全部完成,只需删除标记并打印结果

    这项工作适用于任何长度的行,但是该行不能被 4 整除,最后一部分也将包含余数。

    【讨论】:

      【解决方案4】:

      perl

      perl 可能是更好的选择:

      export cols=4
      perl -ne 'chomp; $fw = 1 + int length()/$ENV{cols}; while(/(.{1,$fw})/gm) { print $1 . " " } print "\n"'
      

      这会重新计算每一行的字段宽度。

      coreutils

      一个 GNU coreutils 替代方案,根据infile 的第一行选择字段宽度:

      cols=4
      len=$(( $(head -n1 infile | wc -c) - 1 ))
      fw=$(echo "scale=0; 1 + $len / 4" | bc)
      
      cut_arg=$(paste -d- <(seq 1 $fw 19) <(seq $fw $fw $len) | head -c-1 | tr '\n' ',')
      

      cut_arg 的值在上述情况下:

      1-5,6-10,11-15,16-
      

      现在将线切割成适当的块:

      cut --output-delimiter=' ' -c $cut_arg infile
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-21
        • 1970-01-01
        • 1970-01-01
        • 2011-07-19
        • 2015-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多