Encontre e substitua usando arquivos com regex

1

OK, vamos supor que eu tenha FileA.txt que contém isso:

string1, 3269
asdf, 8635
ghjk, 8534
foo, 4179
bar, 23490

Gostaria de usar um ou dois arquivos de texto (o que é sempre mais fácil), nos quais posso armazenar isso:

FileB.txt

string1 | 1string
bar | foo

" | " seria um separador, não importaria se tivesse que ser outro arquivo (1string e foo estariam em FileC.txt se esse for o caso).

Eu gostaria de executar uma pesquisa e substituir a operação com as strings para procurar e substituir em FileB.txt (e potencialmente um FileC.txt ), então o resultado seria o seguinte:

1string, 3269
asdf, 8635
ghjk, 8534
foo, 4179
foo, 23490

Alguma ferramenta que eu poderia usar para fazer isso? Obrigado!

    
por graber 07.01.2018 / 21:28

2 respostas

4

Awk solução:

awk 'NR==FNR{ a[$1]=$3; next }$1 in a{ $1=a[$1] }1' FileB.txt FS=',' OFS=',' FileA.txt
  • NR==FNR{ ... } - processando o primeiro arquivo de entrada, ou seja, FileB.txt :
    • a[$1]=$3 - capturando cada valor do terceiro campo $3 na matriz a usando o primeiro campo $1 como índice da matriz / chave
    • next - pula para o próximo registro
  • $1 in a - durante o processamento do segundo arquivo de entrada (ou seja, FileA.txt ), verifique se o primeiro valor do campo $1 ocorre no array a keys:
    • $1=a[$1] - substitua pelo valor de substituição

A saída:

1string,  3269
asdf, 8635
ghjk, 8534
foo, 4179
foo,  23490
    
por 07.01.2018 / 21:36
1

Usando perl e pré-compilando as expressões regulares para eficiência (não muito importante com apenas 2 padrões de pesquisa e substituição, mas muito útil se houver centenas ou milhares):

#!/usr/bin/perl

use strict;

my %rep=();  # hash for storing search patterns with their replacements
my @rep=();  # array for storing search patterns in the order they were seen.

# first arg is the replacement file
my $replacements_file = shift;

open(REP,'<',$replacements_file) || die "Couldn't open $replacements_file: $!\n";
while(<REP>) {
  chomp;
  my ($s, $r) = split / \| /;

  my $search = qr/$s/; # precompile the regex

  $rep{$search} = $r;  # store the search regex and its replacement in a hash

  push @rep, $search;  # use an indexed array to remember the order the patterns
                       # were read in.
};
close(REP);

# main loop: process remaining args and/or stdin, apply each
# search and replace to every input line.

while(<>) {

  foreach my $s (@rep) {
    s/$s/$rep{$s}/;
  };

  print
}

Exemplo de saída:

$ ./replace.pl FileB.txt FileA.txt 
1string, 3269
asdf, 8635
ghjk, 8534
foo, 4179
foo, 23490

Aviso: se o mesmo padrão de pesquisa aparecer mais de uma vez, somente o último será armazenado e usado. A maneira mais fácil de evitar essa limitação é armazenar os padrões de pesquisa e suas substituições correspondentes em dois arrays separados:

#!/usr/bin/perl

use strict;

my (@srch, @reps)=();

my $replacements_file = shift;

open(REP,'<',$replacements_file) || die "Couldn't open $replacements_file: $!\n";
my $count=0;
while(<REP>) {
  chomp;
  my ($s, $r) = split / \| /;

  $srch[$count] = qr/$s/;
  $reps[$count] = $r;
  $count++;
};
close(REP);
$count--;

while(<>) {
  foreach my $i (0..$count) {
    s/$srch[$i]/$reps[$i]/;
  };
  print
}

Não é necessário um hash nesta versão, então usei dois arrays.   @srch para manter os padrões de pesquisa e @reps para manter as sequências de substituição.

    
por 08.01.2018 / 02:56