Próbuję wykonać wymianę wzoru za pomocą scenariusza SED, ale nie działa prawidłowo

próbki_content.txt

288Y2RZDBPX1000000001dhana
JP2F64EI1000000002d
EU9V3IXI1000000003dfg1000000001dfdfds
XATSSSSFOO4dhanaUXIBB7TF71000000004adf
10Q1W4ZEAV18LXNPSPGRTTIDHBN1000000005egw

Wzór.txt.

1000000001 9000000003
1000000002 2000000001
1000000003 3000000001
1000000004 4000000001
1000000005 5000000001

Oczekiwany wynik

288Y2RZDBPX9000000003dhana
JP2F64EI2000000001d
EU9V3IXI3000000001dfg9000000003dfdfds
XATSSSSFOO4dhanaUXIBB7TF74000000001adf
10Q1W4ZEAV18LXNPSPGRTTIDHBN5000000001egw

Jestem w stanie zrobić z samotną wymianą SED jak

sed  's/1000000001/1000000003/g' sample_content.txt

Uwaga:

  • Wzór pasujący nie znajduje się w stałej pozycji.
  • Pojedyncza linia może mieć wiele pasujących wartości do wymiany w przykładzie próbki_content.txt
  • Próbki_content.txt i wzorca .txt ma> 1 milion rekordów

Załącznik do plików Link: https://drive.google.com/open ? Id = 1dvzivkmirequ3YK9KFPM6IE7TTZVRDT_

Czy ktoś może sugerować, jak to może osiągnąć bez wpływu na wydajność?

Zaktualizowano 11-lutego 2018 r.

Po przeanalizowaniu rzeczywistego pliku właśnie dostałem podpowiedź, że wartość klasy w pozycji 30 i 31. . Który pomaga gdzie i wszystko musimy zastosować wymianę.
.. Jeśli Grade AB Następnie zastąp 10-cyfrowy numer telefonu w 41-50 i 101-110
Jeśli klasa BC , wymień 10-cyfrowy numer telefonu w 11-20, 61-70 i 151-160
Jeśli Grade de Wymień 10-cyfrowy numer telefonu w 1-10, 71-80, 151-160 i 181-190

Podobnie jak to widzę 50 unikalnych klas dla 2 miliony rekordów próbek.

{   grade=substr($0,110,2)} // identify grade
{ 
    if (grade == "AB") {
        print substr($0,41,10) ORS substr($0,101,10)
    } else if(RT == "BC"){
        print substr($0,11,10) ORS substr($0,61,10) ORS substr($0,151,10) 
    }

    like wise 50 coiditions
}

Czy mogę wiedzieć, czy to podejście jest wskazane lub jakieś lepsze podejście?

10
Dhanabalan 10 luty 2018, 12:41

3 odpowiedzi

Spróbuj tego. Powinien być szybki.

$ sed -f <(printf 's/%s/%s/g\n' $(<patterns.txt)) contents.txt

Formaty ten formatuje dane `Wzorzec

$ printf 's/%s/%s/g\n' $(<patterns.txt)
s/1000000001/9000000003/g
s/1000000002/2000000001/g
s/1000000003/3000000001/g
s/1000000004/4000000001/g
s/1000000005/5000000001/g

Wszystkie powyższe są następnie podane wraz z substytucją procesu <(...) do prostego {X1}} jako plik skryptowy za pomocą
sed -f Switch = Odczyt SED Polecenia z pliku

$ sed -f <(printf 's/%s/%s/g\n' $(<patterns.txt)) contents.txt
288Y2RZDBPX9000000003dhana
JP2F64EI2000000001d
EU9V3IXI3000000001dfg9000000003dfdfds
XATSSSSFOO4dhanaUXIBB7TF74000000001adf
10Q1W4ZEAV18LXNPSPGRTTIDHBN5000000001egw
6
George Vasiliou 10 luty 2018, 10:12

Czy mógłbyś spróbować śledzić awk i daj mi znać, jeśli ci to pomaga.

roztwór 1st:

awk 'FNR==NR{a[$1]=$2;next}   {for(i in a){match($0,i);val=substr($0,RSTART,RLENGTH);if(val){sub(val,a[i])}};print}' patterns.txt  sample_content.txt

Wynik będzie następujący.

288Y2RZDBPX9000000003dhana
JP2F64EI2000000001d
EU9V3IXI3000000001dfg9000000003dfdfds
XATSSSSFOO4dhanaUXIBB7TF74000000001adf
10Q1W4ZEAV18LXNPSPGRTTIDHBN5000000001egw

Wyjaśnienie roztworu 1st: Dodawanie wyjaśnień TERAZ tutaj:

awk '
FNR==NR{                           ##FNR==NR is a condition which will be TRUE when only first Input_file patterns.txt is being read.
                                   ##FNR and NR both represents line number of Input_file(s) where FNR value will be RESET when a new Input_file is getting read on the other hand NR value will be keep increasing till all Input_file(s) read.
  a[$1]=$2;                        ##creating an array a whose index is first field of line and value is 2nd field of current line.
  next                             ##next will skip all further statements for now.
}
{
for(i in a){                       ##Starting a for loop which traverse through array a all element.
  match($0,i);                     ##Using match function of awk which will try to match index if array a present in variable i.
  val=substr($0,RSTART,RLENGTH);   ##Creating a variable named val which contains the substring of current line substring starts from value of variable RSTART till RLENGTH value.
  if(val){                         ##Checking condition if variable val is NOT NULL then do following:
    sub(val,a[i])}                 ##using sub function of awk to substitute variable val value with array a value of index i.
};
  print                            ##Using print here to print the current line either changed or not changed one.
}
' patterns.txt  sample_content.txt ##Mentioning the Input_file(s) name here.

Rozwiązanie 2. Bez przemierzania przez cały czas do tablicy tak jak pierwsze rozwiązanie wychodzące z tablicy, gdy mecz znajduje się w następujący sposób:

awk '
FNR==NR{                           ##FNR==NR is a condition which will be TRUE when only first Input_file patterns.txt is being read.
                                   ##FNR and NR both represents line number of Input_file(s) where FNR value will be RESET when a new Input_file is getting read on the other hand NR value will be keep increasing till all Input_file(s) read.
  a[$1]=$2;                        ##creating an array a whose index is first field of line and value is 2nd field of current line.
  next                             ##next will skip all further statements for now.
}
{
for(i in a){                       ##Starting a for loop which traverse through array a all element.
  match($0,i);                     ##Using match function of awk which will try to match index if array a present in variable i.
  val=substr($0,RSTART,RLENGTH);   ##Creating a variable named val which contains the substring of current line substring starts from value of variable RSTART till RLENGTH value.
  if(val){                         ##Checking condition if variable val is NOT NULL then do following:
    sub(val,a[i]);print;next}                 ##using sub function of awk to subsitute variable val value with array a value of index i.
};
}
1
' patterns.txt  sample_content.txt ##Mentioning the Input_file(s) name here.
3
RavinderSingh13 10 luty 2018, 10:19

Proste podejście to:

$ cat tst.awk
NR==FNR {
    map[$1] = $2
    next
}
{
    for (old in map) {
        gsub(old,map[old])
    }
    print
}

$ awk -f tst.awk patterns.txt sample_content.txt
288Y2RZDBPX9000000003dhana
JP2F64EI2000000001d
EU9V3IXI3000000001dfg9000000003dfdfds
XATSSSSFOO4dhanaUXIBB7TF74000000001adf
10Q1W4ZEAV18LXNPSPGRTTIDHBN5000000001egw

Podobnie jak inne rozwiązania opublikowane do tej palety, dotyczy to każdej substytucji do całej linii i tak podane przykłady_content.txt zawierające xay i wzorów xcy zamiast xby.

Alternatywnie możesz spróbować tego:

$ cat tst.awk
NR==FNR {
    map[$1] = $2
    re = re sep $1
    sep = "|"
    next
}
{
    head = ""
    tail = $0
    while ( match(tail,re) ) {
        head = head substr(tail,1,RSTART-1) map[substr(tail,RSTART,RLENGTH)]
        tail = substr(tail,RSTART+RLENGTH)
    }
    print head tail
}

$ awk -f tst.awk patterns.txt sample_content.txt
288Y2RZDBPX9000000003dhana
JP2F64EI2000000001d
EU9V3IXI3000000001dfg9000000003dfdfds
XATSSSSFOO4dhanaUXIBB7TF74000000001adf
10Q1W4ZEAV18LXNPSPGRTTIDHBN5000000001egw

To podejście ma kilka zalet:

  1. Wydanoby xby (co podejrzewam, że naprawdę chcesz, jeśli taka sytuacja pojawiła się) w przypadku wspomnianego powyżej
  2. Robi tylko tyle porównań REGEXP na linię próbki_content.txt, jak mogłoby pasować zamiast 1 na linię wzoru .txt dla każdej linii próbki_content.txt
  3. Działa tylko na tym, co pozostało z linii po poprzedniej wymianie, więc przetestowano ciąg ciągłego
  4. To nie zmienia $0, a więc awk nie musi ponownie skompilować i przepełniać ten rekord z każdą subittion.

Powinno więc być dużo szybciej niż oryginalny skrypt przy założeniu, że regexp zbudowany z wzorów

2
Ed Morton 10 luty 2018, 12:11