Execute uma das muitas substituições em muitos arquivos em dois locais específicos

2

Eu tenho cerca de cem mil arquivos, para cada arquivo eu quero fazer o seguinte:

Entre o quinto e sexto caractere no arquivo com o seguinte código ascii: 0x1f , uma string está presente. Agora eu quero que o aplicativo abra um arquivo específico contendo uma lista de todas as substituições, veja depois o formato daquele arquivo de substituições. Se a substituição não estiver no arquivo, escreva o nome do arquivo para stderr, para que eu possa corrigi-lo manualmente mais tarde. Agora entre o 16º eo 17º caractere com o código ascii 0x1f a coisa a substituir aparecerá novamente, entretanto desta vez o campo não é apenas a coisa a substituir, mas uma string de html contendo o que for substituído de uma a várias vezes. Eu só quero que a primeira ocorrência nesse campo seja substituída.

O formato do arquivo de substituições é bastante simples, cada substituição está em sua própria linha e eles são separados por um espaço. Eles são ordenados pelo comprimento da coisa para substituir.

Exemplo

Arquivo de substituições:

CCCC 3
BCC 233
CCA 331
CCB 332
ACC 133
AA 11
AB 12
BA 21
BB 22
CC 33
A 1
B 2

Note que não é garantido que sejam caracteres e números como acima, isso é apenas um exemplo e o arquivo pode conter UTF-8.

Arquivo: (caracteres 0x1f são escritos como ^ _ no exemplo a seguir)

field1^_field2^_field3^_field4^_field5^_BB^_field7^_hai
this field contains a newline^_some UTF-8オイ^_the next field is empty^_^_
another newline^_field14^_field15^_<b>BB</b>stuff BB^_the previous field contains something to replace^_^_^_more fields...

Este arquivo seria transformado em

field1^_field2^_field3^_field4^_field5^_22^_field7^_hai
this field contains a newline^_some UTF-8オイ^_the next field is empty^_^_
another newline^_field14^_field15^_<b>22</b>stuff BB^_the previous field contains something to replace^_^_^_more fields...

Enviei um exemplo real da minha entrada aqui . A saída desejada desse arquivo é aqui ( RYO deve ser substituído por リョ ).

Um pouco de experiência
Algum idiota decidiu que, em vez de criar colunas separadas em nosso banco de dados, ele fez uma única coluna e separou os campos com o caractere 0x1f. Ele também decidiu que não há problema em duplicar as informações que desejo alterar em dois campos diferentes. Eu extraí as informações do banco de dados em um arquivo pr. linha contendo apenas a coluna com os campos, como eu suspeito que é mais fácil trabalhar com, no entanto, se você pode fazer uma declaração que posso dar a um banco de dados SQLite, tudo bem também.

    
por Alice Ryhl 16.05.2015 / 16:21

1 resposta

2

Esse script Perl deve fazer isso. Eu testei no exemplo que você tinha no pastebin e ele funciona como esperado:

#!/usr/bin/env perl
use strict;

my %k; ## This hash will store the target/replacement pairs
## Read the list of replacements
open(my $r,"$ARGV[0]")||die "Couldn't open replacements list\n";
while(<$r>){
    chomp;
    my @F=split(/\s+/);
    $k{$F[0]}=$F[1]
}
close($r);
$/=undef;

open(my $fh, "$ARGV[1]")||die "Couldn't open input file\n";
while(<$fh>){
    ## Read the entire file at once
    $/=undef;
    my @F=split(/\x1f/);
    ## If this exists in the replacements list
    if (defined($k{$F[5]})) {
        ## Modify the 17th field. This will only replace the first
        ## occurence. Use 's///g' for all. 
        $F[16]=~s/$F[5]/$k{$F[5]}/;
        ## Replace the 6th field
        $F[5]=$k{$F[5]};

    }
    ## If it doesn't
    else {
        ## Print the file name to STDERR unless the 5th field
        ## was empty.
        print STDERR "Problematic file: $ARGV[1]\n" unless $F[5]=~/^\s*$/;
    }
    ## print each field separated by '0x1f' again.
    print join "\x1f",@F;


}
close($fh);

Salve isso como fixidiocy.pl no diretório $HOME e cd no diretório que contém os arquivos de destino. Agora, execute-o em cada arquivo, fornecendo o nome do arquivo e o caminho para o arquivo de substituições como argumentos:

for file in *; do 
    perl ~/fixidiocy.pl /path/to/replacements "$file" > "$file".fixed
done
    
por 16.05.2015 / 17:00