-1

タイトルはわかりにくいかもしれませんが、私がやろうとしていることは次のとおりです。

File1 
12=921:5,895:5,813:5,853:5,978:5,807:5,1200:5,1067:5,827:5

File2 
Tom 12 John 921 Mike 813

Output 
Tom=John:5,Mike:5

file2 には file1 の数値の値があり、数値を一致させて文字列値に置き換えたいと考えています。awkで限られた知識でこれを試しましたが、できませんでした。

どんな助けでも感謝します。

4

2 に答える 2

1

を使用する 1 つの方法を次に示しGNU awkます。次のように実行します。

awk -f script.awk file1 file2

の内容script.awk:

BEGIN {
    FS="[ =:,]"
}

FNR==NR {
    a[$1]=$0
    next
}

$2 in a {
    split(a[$2],b)
    for (i=3;i<=NF-1;i+=2) {
        for (j=2;j<=length(b)-1;j+=2) {
            if ($(i+1) == b[j]) {
                line = (line ? line "," : "") $i ":" b[j+1]
            }
        }
    }
    print $1 "=" line
    line = ""
}

結果:

Tom=John:5,Mike:5

または、ここにワンライナーがあります:

awk -F "[ =:,]" 'FNR==NR { a[$1]=$0; next } $2 in a { split(a[$2],b); for (i=3;i<=NF-1;i+=2) for (j=2;j<=length(b)-1;j+=2) if ($(i+1) == b[j]) line = (line ? line "," : "") $i ":" b[j+1]; print $1 "=" line; line = "" }' file1 file2

説明:

awk のフィールド セパレータを、スペース、等号、コロン、またはコンマのいずれかに変更します。

'FNR==NR { ... }' は、引数リストの最初のファイルにのみ当てはまります。

したがって、file1 を処理するとき、awk は列 '1' を配列に追加し、行全体を値としてこの配列要素に割り当てます。

「next」は、スクリプトの残りの処理を単純にスキップし、入力の次の行を読み取ります。

awk が file1 の入力の読み取りを終了すると、file2 の読み取りを続行します。ただし、これは 'FNR' も '1' にリセットするため、awk は file2 の 'FNR==NR' ブロックの処理をスキップします。

file2 の場合: 列 '2' が上記の配列にある場合:

配列要素の値を別の配列に分割します。これにより、基本的に file1 の行全体が分割されます。

ここで、2 つのループを作成します。

最初は file2 のすべての名前をループします

そして 2 番目は (2 番目の) 配列のすべての値をループします (これは基本的に file1 のすべてのフィールドをループします)。

ここで、file2 の名前に続く値が file1 のキー番号の 1 つと等しい場合、「name:number_following_key_number_from_file1」のような行構造を作成します。

ループ中にさらに名前と値が見つかると、4 項構造 '( ... ? ... : ...)' がこれらの要素を行末に追加します。これは if ステートメントのようなものです。すでに行がある場合は、その行の最後にコンマを追加します。それ以外の場合は何もしません。

すべてのループが完了したら、列 '1' と行を出力します。次に、再度使用できるように line 変数を空にします。

HTH。幸運を。

于 2012-12-10T13:51:09.530 に答える
0

以下はテンプレートとして機能する可能性があります。

skrynesaver@busybox ~/ perl -e '$values="12=921:5,895:5,813:5,853:5,978:5,807:5,1200:5,1067:5,827:5";
$data = "Tom 12 John 921 Mike 813";
($line,$values)=split/=/,$values;
@values=split/,/,$values;
$values{$line}="=";
map{$_=~/(\d+)(:\d+)/;$values{$1}="$2";}@values;
if ($data=~/\w+\s$line\s/){
  $data=~s/(\w+)\s(\d+)\s?/$1$values{$2}/g;
}
print "$data\n";
'
Tom=John:5Mike:5
skrynesaver@busybox ~/
于 2012-12-10T12:48:01.137 に答える