Substituição de string no arquivo

3

Eu tenho o seguinte arquivo:

<?xml version="1.0" encoding="utf-8"?>
<!--Generated by crowdin.net-->
  <string name="test" >- test</string>
  <string name="test" >test-test</string>
  <string name="test" >test - test</string>

e gostaria de substituir o en dash pelo seu valor unicode, mas nem todos, apenas o da tag string

Corri vários sed com regex diferente, mas não consegui descobrir. Um deles foi

sed -i.bak "s/-[^-\<\>0-9]/\&#8211\;/g" strings.xml

a saída foi:

<?xml version="1.0" encoding="utf-8"?>
<!-&#8211;enerated by-->
  <string name="test" >&#8211;test</string>
  <string name="test2" >test&#8211;est</string>
  <string name="test3" >test &#8211;test</string>

meu problema é que também está substituindo espaços vazios e o primeiro caracter da segunda palavra. Eu não tenho essa grande experiência com regex e sed . Você poderia, por favor, me explicar o que estou fazendo errado?

Nota: estou usando o OSX.

    
por Blackbelt 01.07.2014 / 12:55

3 respostas

3

Com um recente (para \K e s///r ) perl e supondo que suas tags <string> não aninhem:

perl -0777 -pi.bak -e's{<string.*?>\K.*?(?=</string>)}{$&=~s/-/&#8211;/rg}ges' file.xml
  • -0777 : modo slurp : manipula o arquivo inteiro de uma só vez (para permitir que <string> tags ocupem várias linhas).
  • -p : sed mode
  • -i.bak : edição no local com .bak extension (BTW, de onde algumas implementações de sed tiraram essa ideia)
  • s{...}{...}ges : substitua globalmente ( g ), onde . corresponde também a caracteres de nova linha ( s ) e trate a substituição como perl code para executar ( e ).
  • <string.*?>\K.*?</string> : corresponde de <string...> a </string> , mas não inclui as próprias tags na parte que é correspondida ( \K define onde a porção correspondida começa, e (?=...) é um operador de look-ahead que somente verifica se </string> está lá, mas não o inclui no jogo).
  • %código%. Faça a substituição na parte correspondida ( $&=~s/.../.../rg ). O sinal $& é, na verdade, não modificar r , mas retornar a string substituída.
por 01.07.2014 / 14:46
3

Ufa, depois de algum tempo eu entendi. Esta é uma solução ingênua. a resposta de terdon está mais correta e você deve usar o seu embora:).

sed -Ei.bak "s/(.*<string[^>]*\")(.*)-(.*)/\&#8211;/g" strings.xml

Estou usando Backreferences para me referir a uma string correspondida anteriormente. Estes são etc.

Nesse caso, o sed deve corresponder aos seguintes grupos:

  • (.*<string[^>]*\") - qualquer caractere seguido por uma tag de string abrindo até uma cotação " . Grupo 1
  • (.*) - qualquer coisa depois do " (incluindo agora > ) até o grupo 3. Grupo 2
  • - o traço correspondente
  • (.*) - qualquer coisa após o traço correspondente Grupo 3

Depois eu o substituo pelos grupos previamente combinados e o valor HTML do traço &#8211; , usando \n com n como referência ao grupo n .

Problemas:

Atualmente, estou tentando corrigir alguns problemas, então, por favor, lide comigo:

  1. O grupo 1 também corresponde a dsfjpasj<string
  2. O grupo 1 deve incluir o caractere final da tag da string >
  3. Como Terdon aponta: "isso não funcionará nos casos em que você tem >1 - ou tags ou tags aninhadas que abrangem várias linhas"

Leia mais:

link

    
por 01.07.2014 / 13:37
2

Se eu entendi corretamente, você deseja substituir todos os casos (três no seu exemplo) de - dentro de <strng></string> tags e apenas esses casos. Nesse caso, essas abordagens devem funcionar supondo que seu XML seja são :

  1. Use uma expressão regular e uma ferramenta simples como sed

    sed 's/\(<string[^>]*>[^-]*\)-\([^-]*<\/string\)/\&#8211;/' file.xml 
    
  2. Se o seu arquivo é sempre como no exemplo acima e você pode ter certeza de que suas tags sempre serão <string name="test" ></string> , você pode usar lookbehinds :

    perl -pe 's/(?<=<string name="test" >)([^<]*?)-([^<]*)/$1&#8211;$2/g' file.xml
    
  3. Nenhuma das opções acima funcionará se você tiver mais de um único - nas tags. Para lidar com esses casos, você pode escrever um pequeno script simples que verifica se estamos dentro de <string></string> tags. Isso também deve lidar com tags aninhadas.

    perl -F'<' -lane 'for($i=0;$i<=$#F;$i++){
        $a++ if $F[$i]=~/^string/; 
        $F[$i]=~s/-/&#8211;/g if $a>0; 
        $a-- if $F[$i]=~/^\/string/
    } print join "<",@F' file.xml
    
por 01.07.2014 / 13:53