我有一个数据文件,我需要使用正则表达式进行转换。更具体地说,我需要保持前6列相同,并且从第7列开始,仅选择奇数列,然后将每对连续行的字段放在一起。我知道这听起来有点复杂,所以我将通过一个例子来澄清这一点。这是我的原始数据文件(它可以有任意数量的列):
A B C D E F 11 12 13 14 15 16 17 18
A B C D E F 21 22 23 24 25 26 27 28
A B C D E F 31 31 33 34 35 36 37 38
A B C D E F 41 42 43 44 45 46 47 48
A B C D E F 51 52 53 54 55 56 57 58
A B C D E F 61 62 63 64 65 66 67 68
A B C D E F 71 72 73 74 75 76 77 78
A B C D E F 81 82 83 84 85 86 87 88
我发现我可以保留6个第一列,然后用
删除奇数列awk '{for (i = 1; i <= NF; i++) if (i < 7 || i % 2 == 1) printf $i OFS}; {print ""}
这就是结果:
A B C D E F 11 13 15 17
A B C D E F 21 23 25 27
A B C D E F 31 33 35 37
A B C D E F 41 43 45 47
A B C D E F 51 53 55 57
A B C D E F 61 63 65 67
A B C D E F 71 73 75 77
A B C D E F 81 83 85 87
但之后我必须将每对连续行的字段放在一起,如下所示:
A B C D E F 11 21 13 23 15 25 17 27
A B C D E F 31 41 33 43 35 45 37 47
A B C D E F 51 61 53 63 55 65 57 67
A B C D E F 71 81 73 83 75 85 77 87
我正在考虑使用sed或awk来完成整个过程,因为我的数据文件非常庞大,我需要有效地转换它们,但我也想不出办法进行第二次转换。任何帮助都将受到高度赞赏。
答案 0 :(得分:3)
这是使用GNU awk
的一种方式。像:
awk -f script.awk file.txt
script.awk
的内容:
{
getline line
split(line, array)
k = 6
n = ((NF - k) % 2 == 0) ? 1 : 0
for (i=1; i<=k; i++) {
printf $i OFS
}
for (j=7; j<=NF-n; j+=2) {
x = $j OFS array[j]
printf (j < NF - n) ? x OFS : x "\n"
}
}
结果:
A B C D E F 11 21 13 23 15 25 17 27
A B C D E F 31 41 33 43 35 45 37 47
A B C D E F 51 61 53 63 55 65 57 67
A B C D E F 71 81 73 83 75 85 77 87
答案 1 :(得分:2)
试试这个:
# d.awk
{
if (NR % 2 == 1) {
a = $7
b = $9
c = $11
d = $13
} else {
print $1, $2, $3, $4, $5, $6, a, $7, b, $9, c, $11, d, $13
}
}
结果:
% gawk -f d.awk data
A B C D E F 11 21 13 23 15 25 17 27
A B C D E F 31 41 33 43 35 45 37 47
A B C D E F 51 61 53 63 55 65 57 67
A B C D E F 71 81 73 83 75 85 77 87
答案 2 :(得分:2)
Perl解决方案:
perl -ane '
BEGIN { $, = " " }
if ($. % 2) {
@p = (@F[0..5], @F[grep 1-$_ % 2, 6 .. $#F])
} else {
print @p[0..5], (map { $p[$_], $F[2 * $_ - 6] } 6 .. $#F ), "\n"
}'
答案 3 :(得分:0)
我想出了这个:
{
if (NR % 2 == 1){
for(i = 7; i <= NF; i += 2){
array[i] = $i
}
}
else{
printf "%s %s %s %s %s %s", $1, $2, $3, $4, $5, $6
for(i = 7; i <= NF; i += 2){
printf " %s %s", array[i], $i
}
print ""
}
}
它适用于开放帖子的示例,包含任意数量的字段。我唯一担心的是我的实际数据文件包含2774938个字段,因为我是afk的新手,我不知道这是否是一种有效的方法。
答案 4 :(得分:0)
awk '
NR%2 { split($0,a); next }
{
for(i=7;i<NF;i+=2) {
$(i+1) = $i
$i = a[i]
}
}
1' file
或者如果您更喜欢“可爱”的解决方案,但有一些警告(但可以使用发布的样本数据):
awk '
!(NR%2) { printf fmt,$7,$9,$11,$13 }
{ for (i=8;i<=NF;i+=2) $i="%s"; fmt=$0"\n" }
' file
答案 5 :(得分:0)
这可能适合你(GNU sed):
sed -r 's/(\s?\S+)\s\S+/\1/4g;h;s/.*//;N;s/(\s?\S+)\s\S+/\1/4g;H;g;s/^(.*)(.*\n)\n\1/\1\n\2/;h;s/[^\n]*\n//;:a;s/([^ \n]*)\n([^ \n]*)/\n\2 \1\n/g;s/\n \n?| \n/\n/g;/\n[^\n ]*$/!ba;y/\n/ /;H;x;s/\n.*\n//' file