删除某些列中的数值同时保留减号?

删除某些列中的数值同时保留减号?

我有以下数据框,该数据框在水平和垂直方向上无限延续,仅在奇数列中带有负数:

-1  2  3  4 -5  9
 2  3 -4  5 -6  11

我想要第二、第四和第六完整列(或每个偶数列),而减号仅来自第一、第三和第五(或每个奇数列),所以我得到这个:

- 2   4 - 9
  3 - 5 - 11

最终得到这样的结果:

-2  4 -9
 3 -5 -11

因此,我需要偶数列中的值保持不变,而奇数列中的值,如果有负值,则仅保留 - ,如果有正值,则丢弃它。

有没有办法用 awk/sed 来做到这一点?

据我所知,这大约是:

awk '{ for (i=2;i<=NF;i+=2) $i="" }1' FILE.txt | sed 's/[0-9,.]*//g' 

答案1

道路sed

sed -E '
    s/^(([ \t]*-?[ \t]*[0-9.]+[ \t]+[0-9.]+)*)[ \t]+-?[ \t]*[0-9.]+$/\1/;
    s/[0-9.]+[ \t]+([0-9.]+)/\1/g'

输出:

-2  4 -9
 3 -5 -11

如果列数为奇数,第一个表达式将删除尾随列。它通过查找 0 个或更多对来实现这一点<number> <number>,其中第一个数字可以为负数。

编辑:sed受@mikeserv启发的更短的解决方案:

sed -E '
    s/[0-9.]+[ \t]*([0-9.]*)/\1/g;
    s/[- \t]*$//'

同样的事情perl

perl -lpe 's/^((\s*-?\s*[\d.]+\s*[\d.]+)*)\s+-?\s*[\d.]+$/$1/o; s/[\d.]+\s+([\d.]+)/$1/g'

另一种方式perl(可能是最干净的方式):

perl -lpe '$a = 1; s/([\d.]+\s*)/$a++ % 2 ? "" : $1/eg; s/[-\s]*$//o'

答案2

一个perl一:

$ perl -anle 'BEGIN{$,=" "}
  print map{$_=$F[$_]=~/^-/?"-$F[$_+1]":" $F[$_+1]"}grep{!($_%2)}0..$#F' file
-2  4 -9
 3 -5 -11
  • -an将输入拆分为@F数组
  • BEGIN{$,=" "}将输出字段分隔符设置为空格
  • grep{!($_%2)}0..$#F获取数组中所有偶数索引@F,即奇数元素的索引
  • map{$_=$F[$_]=~/^-/?"-$F[$_+1]":" $F[$_+1]"}检查奇数元素是否以 开头-,然后附加-到下一个偶数元素,否则附加一个空格

答案3

正如@terdon 的回答但没有 sed:

awk '{ for(i=1;i<=NF;i+=2){
         if ($i<0) $(i+1)*=-1;
         $i = "";
       }
       print
     }'

答案4

这是一种方法:

$ awk '{for(i=1;i<=NF;i+=2){if($i<0){$i="-"}else{$i="";} }};1' file |
     sed 's/- */-/g; s/  */ /g'
-2 4 -9
 3 -5 -11

awk脚本会遍历所有奇数列,-如果它们为负数,则将其值设置为 ,如果不是,则将其设置为空。然后,sed删除 a 后面的所有空格-,然后将多个连续空格替换为一个空格。请注意,这意味着对齐方式将被破坏,因为某些字段将包含两个或更多字符,而其他字段将包含一个字符。如果您正在使用字段,那不会是问题,它们只是看起来不漂亮。

相关内容