1

私はawkとsedで遊んでいます。次の形式のファイルがあります

0000098236|Q1.1|one|Q2.1|one|Q3.1|one
0000027965|Q1.5|five|Q1.1|one|Q2.1|one
0000083783|Q1.1|one|Q1.5|five|Q2.1|one
0000027965|Q1.1|one|Q1.1|one|Q1.5|five
0000083983|Q1.1|one|Q1.5|five|Q2.1|one
0000083993|Q1.3|three|Q1.4|four|Q1.2|two

QX.Xを特定の数値に変換したい。私はsedでそれを達成しました:

sed -e "s/\<Q1.1\>/88/g" |
sed -e "s/Q1.2/89/g" |
sed -e "s/Q1.3/90/g" |
sed -e "s/Q1.4/91/g" |
sed -e "s/Q1.5/92/g" |

などなど。これまでのところとても良いです。私がこれをした後、私は得る

0000098236|88|one|88|one|88|one
0000027965|92|five|88|one|88|one
0000083783|88|one|92|five|88|one
0000027965|88|one|88|one|92|five
0000083983|88|one|92|five|88|one
0000083993|90|three|91|four|89|two

区切り文字はパイプです。次に、重複ペアを削除する必要があります

  1. 常に最初の値を保持したい
  2. 残りをペアでグループ化したいので、上記の最初の行で88|oneは 1 つのペアです
  3. 重複ペアを一行で取り出したファイルを作りたい

上記のファイルは、変換を実行すると次のようになります。

0000098236|88|one
0000027965|95|five|88|one
0000083783|88|one|92|five
0000027965|88|one|88|one
0000083983|88|one|92|five
0000083993|90|three|91|four|89|two

awk と配列を使用しようとしましたが、機能しません。

4

4 に答える 4

2
sed -r ':a s#([0-9]+\|[a-z]+)(.*)\1#\1\2#; ta; s#\|\|+#|#g; s#\|$##' FILE
0000098236|88|one
0000027965|92|five|88|one
0000083783|88|one|92|five
0000027965|88|one|92|five
0000083983|88|one|92|five
0000083993|90|three|91|four|89|two
于 2012-04-19T07:47:51.873 に答える
2

これにより、前処理の必要がなくなります。小数点以下の桁が置換の選択に重要であると想定しています。

awk '
BEGIN {
    r = "88 89 90 91 92";
    split(r, rep);
    FS = OFS = "|"
}
{
    delete seen;
    cf = i = 2;
    while (cf < NF) {
        split($cf, a, ".");
        newval = rep[a[2]];
        if (!seen[newval]) {
            $i = newval;
            $(i + 1) = $(cf + 1)
            seen[newval] = 1;
            nf = i + 1;
            i += 2;
        };
        cf += 2
    };
    NF = nf;
    print
}' inputfile
于 2012-04-25T04:47:48.743 に答える
1

TXR:

@(do (defun rem-dupes (pairs : recur)
       (if (null pairs) 
         nil
         (let ((front (first pairs))
               (tail (rem-dupes (rest pairs) t)))
           (if (memqual front tail)
             (if recur
               (remqual front tail)
               (cons front (remqual front tail)))
             (cons (first pairs) tail))))))
@(collect :vars nil)
@(freeform 1)
@id|@(coll)@left|@right@/[|\n]/@(end)
@(bind pairs @(rem-dupes [mapcar list left right]))
@(set left @[mapcar first pairs])
@(set right @[mapcar second pairs])
@(output)
@id@(rep)|@left|@right@(end)
@(end)
@(end)

走る:

$ txr data.txr data.txt
0000098236|88|one
0000027965|92|five
0000083783|88|one|92|five
0000027965|88|one|92|five
0000083983|88|one|92|five
0000083993|90|three|91|four|89|two
于 2012-04-19T06:59:18.907 に答える
0

これはあなたのために働くかもしれません:

sed ':a;s/\(\([0-9]*|[^|]*\).*\)|\2/\1/;ta' file
0000098236|88|one
0000027965|92|five|88|one
0000083783|88|one|92|five
0000027965|88|one|92|five
0000083983|88|one|92|five
0000083993|90|three|91|four|89|two

実際、sed の 1 つのインスタンスを使用して、すべてのファイル処理を実行できます。

cat <<\! >file.sed
> 1{x;s/$/.1|88.2|89.3|90.4|91.5|91/;x}  # stuff lookup into hold space .key|value
> s/|Q[^.]*/|/g                          # guessing here - remove Q and number prefix
> :a;s/\(\(\.[^|]*|[^|]*\).*\)|\2/\1/;ta # remove duplicate fields
> G                                      # append newline and lookup table
> :b;s/\(\.[^|]*\)\(.*\n.*\)\1|\([^.]*\)/\3\2/;tb # replace key with value from lookup
> s/\n.*//                               # remove lookup table
> !
sed -f file.sed original_file
0000098236|88|one
0000027965|91|five|88|one
0000083783|88|one|91|five
0000027965|88|one|91|five
0000083983|88|one|91|five
0000083993|90|three|91|four|89|two
于 2012-04-19T12:15:56.077 に答える