Tengo un archivo que se parece a esto:
<table name="content_analyzer" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer2" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer_items" primary-key="id">
<type="global" />
</table>
Necesito extraer cualquier cosa entre las comillas que siguen name=, es decir content_analyzer, content_analyzer2y content_analyzer_items.
Estoy haciendo esto en una caja de Linux, por lo que una solución que use sed, perl, grep o bash está bien.
regex
perl
sed
html-parsing
text-extraction
vaquero
fuente
fuente

Respuestas:
Dado que necesita hacer coincidir el contenido sin incluirlo en el resultado (debe coincidir,
name="pero no es parte del resultado deseado) se requiere alguna forma de coincidencia de ancho cero o captura de grupo. Esto se puede hacer fácilmente con las siguientes herramientas:Perl
Con Perl, puede usar la
nopción para recorrer línea por línea e imprimir el contenido de un grupo de captura si coincide:perl -ne 'print "$1\n" if /name="(.*?)"/' filenameGNU grep
Si tiene una versión mejorada de grep, como GNU grep, puede tener la
-Popción disponible. Esta opción habilitará una expresión regular similar a Perl, lo que le permitirá usar\Kuna búsqueda retrospectiva abreviada. Restablecerá la posición de coincidencia, por lo que cualquier cosa antes de que sea de ancho cero.grep -Po 'name="\K.*?(?=")' filenameLa
oopción hace que grep imprima solo el texto coincidente, en lugar de la línea completa.Vim - Editor de texto
Otra forma es utilizar un editor de texto directamente. Con Vim, una de las diversas formas de lograr esto sería eliminar las líneas sin
name=y luego extraer el contenido de las líneas resultantes::v/.*name="\v([^"]+).*/d|%s//\1Grep estándar
Si no tiene acceso a estas herramientas, por alguna razón, se podría lograr algo similar con grep estándar. Sin embargo, sin mirar alrededor, será necesario limpiarlo más tarde:
grep -o 'name="[^"]*"' filenameUna nota sobre cómo guardar resultados
En todos los comandos anteriores, se enviarán los resultados a
stdout. Es importante recordar que siempre puede guardarlos conectándolos a un archivo agregando:hasta el final del comando.
fuente
grep):grep -Po '.*name="\K.*?(?=".*)'.*un lado, espero que no se enoje conmigo. Me gustaría preguntar, ¿ve algún beneficio de un partido sin codicia sobre "cualquier cosa excepto""? No tome esto como una pelea, solo tengo curiosidad y no soy un experto en expresiones regulares. Además, la\Kpropina, muy bonita. Gracias Dennis..*, puedes hacerlogrep -Po '(?<=name=").*?(?=")'. Se\Kpuede usar para taquigrafía, pero en realidad solo es necesario si la coincidencia a su izquierda es de longitud variable. En casos como este, la razón para usar alternativas es bastante obvia. Las operaciones poco codiciadas se ven un poco más ordenadas ([^"]*versus.*?y no tienes que repetir el personaje principal. No sé sobre la velocidad. Eso depende mucho del contexto, creo. Espero que sea útil.\K(después de investigarlo) y eliminé el.*fue el mismo: hacer que se vea bonito (más simple). Y nunca pensé en usar en.*?lugar de la "forma tradicional" que aprendí de alguna parte. Pero la falta de codicia aquí realmente tiene sentido. Gracias Dennis, mis mejores deseos.La expresión regular sería:
.+name="([^"]+)"Entonces la agrupación estaría en el \ 1
fuente
Si está utilizando Perl, descargue un módulo para analizar XML: XML :: Simple , XML :: Twig o XML :: LibXML . No reinventes la rueda.
fuente
<type="global"por ejemplo), por lo que la mayoría de los analizadores XML simplemente se quejan y mueren.Se debe utilizar un analizador HTML para este propósito en lugar de expresiones regulares. Un programa de Perl que utiliza
HTML::TreeBuilder:Programa
#!/usr/bin/env perl use strict; use warnings; use HTML::TreeBuilder; my $tree = HTML::TreeBuilder->new_from_file( \*DATA ); my @elements = $tree->look_down( sub { defined $_[0]->attr('name') } ); for (@elements) { print $_->attr('name'), "\n"; } __DATA__ <table name="content_analyzer" primary-key="id"> <type="global" /> </table> <table name="content_analyzer2" primary-key="id"> <type="global" /> </table> <table name="content_analyzer_items" primary-key="id"> <type="global" /> </table>Salida
fuente
esto podría hacerlo:
perl -ne 'if(m/name="(.*?)"/){ print $1 . "\n"; }'fuente
Aquí hay una solución que utiliza HTML tidy y xmlstarlet:
htmlstr=' <table name="content_analyzer" primary-key="id"> <type="global" /> </table> <table name="content_analyzer2" primary-key="id"> <type="global" /> </table> <table name="content_analyzer_items" primary-key="id"> <type="global" /> </table> ' echo "$htmlstr" | tidy -q -c -wrap 0 -numeric -asxml -utf8 --merge-divs yes --merge-spans yes 2>/dev/null | sed '/type="global"/d' | xmlstarlet sel -N x="http://www.w3.org/1999/xhtml" -T -t -m "//x:table" -v '@name' -nfuente
Vaya, el comando sed debe preceder al comando tidy, por supuesto:
echo "$htmlstr" | sed '/type="global"/d' | tidy -q -c -wrap 0 -numeric -asxml -utf8 --merge-divs yes --merge-spans yes 2>/dev/null | xmlstarlet sel -N x="http://www.w3.org/1999/xhtml" -T -t -m "//x:table" -v '@name' -nfuente
Si la estructura de su xml (o texto en general) es fija, la forma más fácil es usar
cut. Para su caso específico:echo '<table name="content_analyzer" primary-key="id"> <type="global" /> </table> <table name="content_analyzer2" primary-key="id"> <type="global" /> </table> <table name="content_analyzer_items" primary-key="id"> <type="global" /> </table>' | grep name= | cut -f2 -d '"'fuente