Pregunta

Tengo un archivo HTML y me gustaría extraer el texto entre las etiquetas y <li> </li>. Por supuesto, hay un millón de maneras de hacer esto, pero pensé que sería útil para conseguir más en el hábito de hacer esto en simples comandos shell:

awk '/<li[^>]+><a[^>]+>([^>]+)<\/a>/m' cities.html

El problema es que esta imagen Impresiones todo , mientras que yo simplemente quiero imprimir el partido entre paréntesis - ([^>]+) - ya sea awk no soporta esto, o yo soy incompetente. Este último parece más probable. Si usted quiere aplicar la expresión regular suministrada a un archivo y extraer sólo los partidos determinados, ¿cómo hacerlo? Ya sé una media docena de otras maneras, pero no me siento como dejar awk ganar esta ronda;)

Edit: Los datos no se bien estructurado, así que usar partidos posicionales ($1, $2, etc.) es un no-go

.
¿Fue útil?

Solución

Por su script, si usted puede conseguir lo que quiere (que significa <li> y la etiqueta es <a> en una línea.);

$ cat test.html | awk 'sub(/<li[^>]*><a[^>]*>/,"")&&sub(/<\/a>.*/,"")'

o

$ cat test.html | gawk '/<li[^>]*><a[^>]*>(.*?)<\/a>.*/&&$0=gensub(/<li[^>]*><a[^>]*>(.*?)<\/a>.*/,"\\1", 1)'

El primero es que cada awk, segundo es para awk GNU.

Otros consejos

Si quieres hacer esto en el caso general, donde las etiquetas lista puede contener cualquier tipo de código HTML legal, entonces awk es la herramienta equivocada. La herramienta adecuada para el trabajo sería un analizador de HTML, que se puede confiar para conseguir corregir todos los pequeños detalles de análisis de HTML, incluyendo variantes de HTML y HTML con formato incorrecto.

Si usted está haciendo esto para un caso especial, donde se puede controlar el formato HTML, entonces usted puede ser capaz de hacer el trabajo para usted awk. Por ejemplo, vamos a suponer que se puede garantizar que cada elemento de la lista no ocupa más de una línea, siempre finaliza con </li> en la misma línea, no contiene ningún marcado (por ejemplo, una lista que contiene una lista), entonces se puede utilizar awk a hacer esto, pero hay que escribir un programa awk entera que primero encuentra líneas que contienen elementos de la lista, a continuación, utiliza los comandos de otra awk para encontrar la subcadena le interesa.

Pero, en general, awk es la herramienta equivocada para este trabajo.

gawk -F'<li>' -v RS='</li>' 'RT{print $NF}' file

funcionó bastante bien para mí.

Hay varias cuestiones que veo:

  • El patrón tiene una 'M' de fuga que es significativo para los partidos de varias líneas en Perl, AWK, pero no utiliza expresiones regulares compatibles con Perl. (Al menos, no GNU) awk (estándar no lo hace.)
  • Haciendo caso omiso de eso, el patrón parece buscar un 'elemento de la lista comenzar' seguido de un ancla '<a>' a '</a>', no el elemento de la lista final.
  • Usted busca para cualquier cosa que no es un '>' como el cuerpo del anclaje; eso no es automáticamente mal, pero podría ser más habitual para buscar cualquier cosa que no es '<', o cualquier cosa que no es ni.
  • Awk no hace búsquedas de múltiples líneas.
  • en AWK, '$1' denota el primer campo, donde los campos están separados por los caracteres separador de campo, que por defecto a espacio en blanco.
  • En nawk clásica (como se documenta en el 'sed & awk' libro de la vendimia 1991) no tiene un mecanismo para tirar subcampos de partidos, etc.

No está claro que Awk es la herramienta adecuada para este trabajo. De hecho, no está del todo claro que las expresiones regulares son la herramienta adecuada para este trabajo.

Realmente no sé awk, ¿qué hay de Perl en su lugar?

tr -d '\012' the.html | perl \
-e '$text = <>;' -e 'while ( length( $text) > 0)' \
-e '{ $text =~ /<li>(.*?)<\/li>(.*)/; $target = $1; $text = $2; print "$target\n" }'

1) eliminar los saltos de línea de archivo, tubería a través de Perl

2) inicializar una variable con el texto completo, iniciar un bucle hasta que el texto se ha ido

3) hacer un partido "no codiciosa" para la materia delimitada por las etiquetas list-item, guardar e imprimir el objetivo, establecido para el próximo paso

tiene sentido? (Advertencia, no probar este código a mí mismo, que tenga que ir a casa pronto ...)

P.S. - "Perl -n" es el modo Awk (nawk?). Perl es en gran parte un superconjunto de Awk, por lo que nunca se molestó en aprender Awk.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top