Corresponder e remover primeiro e segundo padrão dentro de tags xml

0

Como posso combinar e remover primeiro e segundo padrão dentro de tags xml usando sed ou awk?

Aqui está o exemplo

<data>A78-1-1134-HI-1</data>
<data>T78-12-1346-AG-2</data>
<data>G78-4-2156-Ag-6</data>
<data>A78-10-1971-Hh-10</data>

Este é o resultado que estou tentando obter:

<data>1134</data>
<data>1346</data>
<data>2156</data>
<data>1971</data

Pode ser feito em uma linha? Isso é o que eu tentei:

sed 's/^.*<data>[[:alnum:]]-[0-9]-/<data>/g;s/-[a-Z].*<\/data>$//g'

Ou removendo apenas um primeiro padrão, quando uso o sed para imprimir, ele funciona:

sed -n 's/^.*<data>.*[[:alnum:]]-[0-9]-/<data>/p' file.xml | grep data

Mas este comando não funcionará:

sed 's/^.*<data>.*[[:alnum:]]-[0-9]-/<data>/' file.xml
    
por milan_K 20.04.2013 / 17:58

3 respostas

0

Aqui estão algumas soluções:

  1. Se o seu arquivo é realmente tão simples quanto o seu exemplo, você pode fazê-lo com este script gawk . Isso pressupõe que seu arquivo não contém nada além de data entradas, conforme descrito na sua pergunta.

    gawk -F"-" '{print "<data>"$3"</data>"}' file.xml
    
    • -F"-" diz ao gawk para considerar - como o separador de campo, o script então imprime o terceiro campo.


  2. Para arquivos um pouco mais complexos que incluam linhas que você não deseja, isso só será impresso se os primeiros campos ($1~/data/ ) e último ( $NF~/data/ ) contiverem data :

    gawk -F"-" '($1~/data/ && $NF~/data/){print "<data>"$3"</data>"}' file.xml
    
  3. Se o seu arquivo puder ter muitas entradas <data> e você se importar apenas com as que se parecem com A1-2B-C3-4D :

    perl -ne '/(<data>).+?-.+?-(.+?)\-.+(<\/data>)/ && do{print "$1$2$3\n"}' file.xml
    

    -ne significa aplicar esse script a cada linha do arquivo de entrada. Em Perl (e muitas outras ferramentas), os parênteses permitem a captura de correspondências de expressões regulares. Aqui, estou capturando três padrões, as tags de abertura e fechamento ( $1 e $3 ), portanto, não preciso digitá-las duas vezes e o padrão que estamos procurando, $2 .

    Se você precisar ser mais específico, use isso para permitir apenas caracteres alfanuméricos no primeiro campo e apenas dígitos nos outros:

    perl -ne '/(<data>)[\w\d]+?-\d+?-(\d+?)\-.+(<\/data>)/ && do{print "$1$2$3\n"}' file.xml
    
  4. Isso tudo pressupõe que suas tags <data> e </data> estejam na mesma linha. Se não estiverem, você pode fazer algo assim:

    perl -ne '
     $d++ if /<data>/; 
      /[\w\d]+?-\d+?-(\d+?)\-.+/ && do{
                 print "<data>$1</data>\n" if $d>0
            }; 
     $d-- if /<\/data>/; 
    ' file.xml
    

    $d será positivo se estivermos dentro de <data></data> tags. Se estivermos e encontrarmos uma linha que corresponda à expressão regular, imprima.

ATUALIZAÇÃO:

Se você deseja editar o arquivo, não apenas imprimir seu conteúdo, mas realmente alterar o arquivo original, use:

perl -i -ne 's/(<data>).+?-.+?-(.+?)\-.+(<\/data>)/$1$2$3/; print' file.xml
    
por 20.04.2013 / 19:41
1

Você está usando as ferramentas erradas para o trabalho. Não analise XML com expressões regulares, você vai entender errado. (Isso é (a) porque é teoricamente impossível - o XML não é um idioma regular e (b) porque suas tentativas práticas podem funcionar em alguns documentos XML, mas inevitavelmente falharão em outros.)

Com o XSLT 2.0, esta é uma transformação trivial.

<xsl:template match="data">
  <xsl:copy>
    <xsl:value-of select="tokenize(., '-')[3]"/>
  </xsl:copy>
</xsl:template>
    
por 20.04.2013 / 23:23
0

Parece que suas repetições não estão especificadas corretamente. Além disso, acho mais fácil usar subexpressões para extrair substrings. Eu não sei suas especificações exatas para dados correspondentes, mas isso funciona para seus dados de amostra na pergunta (eu acho que é compatível com POSIX):

sed 's/<data>[[:alnum:]]\{1,\}-[0-9]\{1,\}-\([0-9]\{1,\}\)-[[:alnum:]]\{1,\}-[0-9]\{1,\}/<data>/' file.xml

Se você tiver o GNU sed à sua disposição, poderá aproveitar as extensões para Expressões regulares estendidas para obter uma expressão mais simples:

sed -r 's/^.*<data>[[:alnum:]]+-[0-9]+-([0-9]+)-[[:alnum:]]+-[0-9]+/<data>/' file.xml
    
por 20.04.2013 / 18:32

Tags