Expressions régulières dynamiques dans awk

Nov 22 2020

J'ai des fichiers texte comme

1.txt

AA;00000;
BB;11111;
GG;22222;

2.txt

KK;WW;55555;11111;
KK;FF;ZZ;11111;
KK;RR;YY;11111;

Je génère cette sortie 3.txt

AA;00000;
BB;11111;KK;WW;55555;FF;ZZ;RR;YY
GG;22222;

avec ce script .awk (je l'utilise sous Windows avec cmd)

#!/usr/bin/awk -f 

NR != FNR {
    exit
}
{
    printf "%s", $0 } /^BB/ { o = "" while (getline tmp < ARGV[2]) { n = split (tmp,arr,";") for (i=1; i<=n; i++) if(!match($0,arr[i]) && !match(o,arr[i]))
                o=o arr[i]";"
    }
    printf "%s", o
}
{
    print ""
}

L'utilisation est awk -f script.awk 1.txt 2.txt

Cela semble aller mais considérez cette situation

1.txt

AA;BB;

2.txt

CC;DD;BB;AA;

remplacez maintenant de cette manière

AAest remplacé par d(2)
BBest remplacé par http://a.o/f/i.p?t=1
CCest remplacé par Link
DDparA_x-y.7z

le script ne peut pas générer 3.txt

AA;BB;CC;DD;

ou, en utilisant du texte remplacé, il ne peut pas générer cette sortie de texte 3.txt

   d(2);http://a.o/f/i.p?t=1;Link;A_x-y.7z;

Vous pouvez voir que les champs en double comme AA, BBsont supprimés de la sortie 3.txt car le script fonctionne de cette manière.

Je soupçonne que cela a à voir avec le fait d' (...)être pris comme un regroupement REGEX match()car le premier paramètre est un REGEX et en passant $0et o les deux seront traités comme des "Expressions régulières dynamiques * en awkparole

Réponses

1 EdMorton Nov 22 2020 at 23:36
$ cat tst.awk BEGIN { FS=OFS=";" } { key = $(NF-1) }
NR == FNR {
    for (i=1; i<(NF-1); i++) {
        if ( !seen[key,$i]++ ) { map[key] = (key in map ? map[key] OFS : "") $i
        }
    }
    next
}
{ print $0 map[key] }

$ awk -f tst.awk 2.txt 1.txt
AA;00000;
BB;11111;KK;WW;55555;FF;ZZ;RR;YY
GG;22222;

Ce qui précède utilise juste des chaînes littérales dans une recherche de hachage d'index de tableau, donc peu importe les caractères que vous avez dans votre entrée. Si vous voulez que votre entrée à traiter comme des chaînes littérales alors ne pas utiliser les fonctions regexp ou opérateurs (par exemple match(), ~, sub()) sur elle, à des fonctions de chaîne d'utilisation / opérateurs (par exemple index(), ==, substr(), in).