8

正規表現で変換する必要があるデータ ファイルがあります。より具体的には、最初の 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を使用してプロセス全体を作成することを考えていましたが、2番目の変換も行う方法がわかりませんでした。どんな助けでも大歓迎です。

4

6 に答える 6

4

を使用する 1 つの方法を次に示し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 
于 2012-10-23T11:06:40.740 に答える
3

これを試して:

# 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
于 2012-10-23T10:05:13.753 に答える
3

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"
    }'
于 2012-10-23T10:08:07.740 に答える
1

私はこれを思いつきます:

{
    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を初めて使用するため、これが効率的な方法であるかどうかはわかりません。

于 2012-10-23T11:16:53.593 に答える
1

これはうまくいくかもしれません(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
于 2012-10-23T19:02:10.690 に答える
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
于 2012-10-23T17:38:57.663 に答える