Domanda

Ho un file HTML e vorrei estrarre il testo tra <li> e </li> tag. Ci sono naturalmente un milione di modi per fare questo, ma ho pensato che sarebbe stato utile per ottenere più l'abitudine di fare questo in semplici comandi di shell:

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

Il problema è che questo stampe tutto , mentre voglio semplicemente stampare la partita tra parentesi - ([^>]+) - sia awk non supporta questo, o io sono incompetenti. Quest'ultimo sembra più probabile. Se si voleva applicare la regex fornito in un file ed estrarre solo le partite specificati, come lo faresti? So già una mezza dozzina di altri modi, ma non mi sento come lasciare awk vincere questo round;)

Modifica: I dati non è ben strutturato, in modo da utilizzare le partite di posizione ($1, $2, etc.) è un no-go

.
È stato utile?

Soluzione

Per lo script, se è possibile ottenere ciò che si vuole (significa <li> e tag <a> è in una linea.);

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

o

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

Il primo è per ogni awk, secondo è per GNU awk.

Altri suggerimenti

Se si vuole fare questo nel caso generale, in cui lista i tag possono contenere qualsiasi codice HTML legale, quindi awk è lo strumento sbagliato. Lo strumento giusto per il lavoro sarebbe un parser HTML, che ci si può fidare di ottenere corretta tutti i piccoli dettagli di parsing del codice HTML, tra cui le varianti di HTML e HTML malformato.

Se si sta facendo questo per un caso particolare, in cui è possibile controllare la formattazione HTML, allora si può essere in grado di rendere il lavoro awk per voi. Per esempio, supponiamo che si può garantire che ogni elemento della lista non occupa più di una riga, è sempre terminato con </li> sulla stessa linea, non contiene nessun marcatore (ad esempio un elenco che contiene un elenco), quindi è possibile utilizzare awk per fare questo, ma è necessario scrivere un programma awk intero che trova prima righe che contengono elementi della lista, quindi utilizza i comandi altro awk per trovare solo la sottostringa che ti interessa.

Ma in generale, awk è lo strumento sbagliato per questo lavoro.

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

Ha funzionato abbastanza bene per me.

Ci sono diverse questioni che vedo:

  • Il modello ha una 'm' di uscita, che è significativo per il multi-linea di partite in Perl, ma Awk non usa le espressioni regolari compatibili con Perl. (Almeno, standard (non-GNU) awk non lo fa.)
  • Ignorando che, il modello sembra cercare un 'elemento della lista inizio' seguito da un ancoraggio '<a>' a '</a>', non è la voce di elenco finale.
  • Si cerca per tutto ciò che non è un '>' come il corpo del tassello; questo non è automaticamente sbagliato, ma potrebbe essere più usuale per la ricerca di tutto ciò che non è '<', o qualsiasi cosa che non è né.
  • Awk non fa ricerche multilinea.
  • In Awk, '$1' denota il primo campo, in cui i campi sono separati da caratteri separatori di campo, che predefinito spazi bianchi.
  • In nawk classica (come documentato nel 'sed & awk' libro dell'annata 1991) non ha un meccanismo in atto per tirare sotto-campi di partite, ecc.

Non è chiaro che Awk è lo strumento giusto per questo lavoro. In effetti, non è del tutto chiaro che le espressioni regolari sono lo strumento giusto per questo lavoro.

Non so davvero awk, come su Perl, invece?

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) rimuovere nuove righe da file, tubo attraverso perl

2) inizializzare una variabile con il testo completo, avviare un ciclo fino a quando il testo è andato

3) fare una partita di "non greedy" per le cose delimitata da tag list-item, salvare e stampare il target, istituito per il prossimo passaggio

ha senso? (Attenzione, non abbiamo provato questo codice me stesso, hanno bisogno di tornare a casa presto ...)

P.S. - "perl -n" è la modalità Awk (nawk?). Perl è in gran parte un superset di Awk, quindi non ho mai preso la briga di imparare Awk.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top