Ignora parte da string com sed

4

Eu tenho arquivos com texto formatado assim:

untranslatedString : "translated string",

e preciso substituir os caracteres na parte "string traduzida" por sua representação cirílica. Eu uso algo assim:

paste <(sed 's/\([^:]\+:\)\([^:]\+\)//' resources.js) <(sed 's/[^:]\+:\([^:]\+\)//;y/abc/абц/' resources.js)

(abc / абц / part é realmente mais longo e inclui todos os caracteres, isto é para fins ilustrativos).

problema surge em linhas como esta:

abcTestString : "abc {ccb} bbc",

tudo entre {} deve ser deixado no estado original, ou seja. personagem não deve ser substituído. resultado deve ser:

abcTestString : "aбц {ccb} ббц",

e não

abcTestString : "aбц {ццб} ббц",

Além disso, pode haver várias {} partes por linha.

Como posso fazer isso?

    
por Vanja Grujic 04.12.2017 / 14:37

3 respostas

3

Se você está bem com o uso de perl

$ s='abcTestString : "abc {ccb} bbc",'
$ echo "$s" | perl -Mopen=locale -Mutf8 -F: -lane '
               $F[-1]=~s/\{[^{}]+\}(*SKIP)(*F)|[a-z]+/$&=~tr|abc|абц|r/ge;
               print join ":",@F'
abcTestString : "абц {ccb} ббц",
  • -Mopen=locale -Mutf8 configurações do unicode (graças a essa maravilhosa resposta tr analog para caracteres unicode? )
  • -F: -lane use : como separador de campo, salvo em @F array (consulte link para outros opções)
  • $F[-1] último campo de @F array
  • \{[^{}]+\}(*SKIP)(*F)|[a-z]+ aqui dizemos que [a-z]+ porção precisa corresponder, mas \{[^{}]+\} deve ser deixado como está
  • $&=~tr|abc|абц|r realiza a transliteração para a parte correspondente
  • ge o modificador g para substituir todas as correspondências, e modificador para permitir o código Perl na seção de substituição


Se este é um código muito grande para manipular a partir da linha de comando, altere-o para um programa

$ echo "$s" | perl -MO=Deparse -Mopen=locale -Mutf8 -F: -lane '
               $F[-1]=~s/\{[^{}]+\}(*SKIP)(*F)|[a-z]+/$&=~tr|abc|абц|r/ge;
               print join ":",@F'
BEGIN { $/ = "\n"; $\ = "\n"; }
use open (split(/,/, 'locale', 0));
use utf8;
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    our @F = split(/:/, $_, 0);
    $F[-1] =~ s[\{[^{}]+\}(*SKIP)(*F)|[a-z]+][use utf8 ();
    $& =~ tr/abc/\x{430}\x{431}\x{446}/r;]eg;
    print join(':', @F);
}
    
por 04.12.2017 / 15:28
3

Se você quiser ficar com sed :

sed 's/"/"_/;:l
  s/_[^{]*/&_/;h
  s/.*_\(.*\)_.*//
  y/abc/абц/;G
  s/\(.*\)\n\(.*\)_.*_\([^}]*}\)\{0,1\}/_/
  /_$/!bl
  s/_//'

Um sublinhado é usado como marca durante o processamento. Se os sublinhados puderem fazer parte do arquivo, use um delimitador diferente.

A idéia é marcar uma parte da string, salvar uma cópia para manter espaço, remover tudo o que estiver fora das marcas, fazer sua conversão, recuperar a cópia, compor uma string com a parte convertida e mover o sublinhado para frente. Se houver uma parte em {} , pule isso.

Eu posso dar uma explicação mais detalhada, se você estiver interessado.

    
por 04.12.2017 / 16:11
3
sed -rf <(echo ':l'; printf 's/("| [^{]*)%s/\1%s/g\n' a а b б c ц; echo 'tl') input.txt

De forma mais concisa, mas também mais propensa a erros, porque a expressão sed está entre aspas duplas, não entre aspas simples, por isso bash caracteres especiais devem ser ignorados, por exemplo, o sinal $ .

sed -r ":l; $(printf 's/("| [^{]*)%s/\1%s/g;' a а b б c ц) tl" input.txt

Explicação (o primeiro comando foi obtido)

sed -f script-file - adiciona o conteúdo do arquivo script aos comandos a serem executados.

<() - substituição de processo. Ele permite representar os comandos de saída como um arquivo e passá-lo para o comando, que está esperando um arquivo.

echo ':l'; printf 's/("| [^{]*)%s/\1%s/g\n' a а b б c ц; echo 'tl' - está convertendo para a próxima sequência de comandos de sed :

:l
s/("| [^{]*)a/а/g
s/("| [^{]*)b/б/g
s/("| [^{]*)c/ц/g
tl

Teste:

Entrada

abcTestString : "abc {bcb} bbc",
abcTestString : "bbc {acb} bbc {bcb}",
abcTestString : "acc {cab} {ccb} bbc",
abcTestString : "cbc {ccb} bac {aca} bac",

Resultado

abcTestString : "абц {bcb} ббц",
abcTestString : "ббц {acb} ббц {bcb}",
abcTestString : "ацц {cab} {ccb} ббц",
abcTestString : "цбц {ccb} бац {aca} бац",
    
por 05.12.2017 / 13:09