Question

J'ai un fichier HTML et que vous souhaitez extraire le texte entre les balises <li> et </li>. Il y a bien sûr un million de façons de le faire, mais je pensais que ce serait utile d'obtenir plus l'habitude de le faire dans les commandes shell simples:

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

Le problème est, cette impression tout alors que je veux simplement imprimer le match entre parenthèses - ([^>]+) - soit awk ne supporte pas, ou je suis incompétent. Ce dernier semble plus probable. Si vous voulez appliquer la regex fournie dans un fichier et extraire uniquement les matches spécifiques, comment feriez-vous? Je sais déjà une demi-douzaine d'autres moyens, mais je ne me sens pas comme laisser awk gagner ce tour;)

Edit: Les données ne sont pas bien structuré, donc en utilisant les matchs de position ($1, $2, etc.) est un no-go

.
Était-ce utile?

La solution

Par votre script, si vous pouvez obtenir ce que vous voulez (cela signifie <li> et la balise de <a> est dans une ligne.);

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

ou

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

La première est pour chaque awk, deuxième est pour gnu awk.

Autres conseils

Si vous voulez faire dans le cas général, où vos balises de liste peut contenir des balises HTML juridique, alors awk est le mauvais outil. L'outil pour le travail serait un analyseur HTML, que vous pouvez faire confiance pour obtenir correcte tous les petits détails de l'analyse syntaxique HTML, y compris les variantes de HTML et HTML malformé.

Si vous faites cela pour un cas particulier, où vous pouvez contrôler la mise en forme HTML, alors vous pourriez être en mesure de faire fonctionner awk pour vous. Par exemple, supposons que vous pouvez garantir que chaque élément de la liste occupe jamais plus d'une ligne, est toujours terminé par </li> sur la même ligne, ne contient aucun balisage (par exemple une liste qui contient une liste), vous pouvez utiliser awk à faire cela, mais vous devez écrire un programme awk tout qui trouve d'abord les lignes qui contiennent des éléments de la liste, puis utilise d'autres commandes awk pour trouver la sous-chaîne qui vous intéresse.

Mais en général, awk est le mauvais outil pour ce travail.

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

A travaillé assez bien pour moi.

Il y a plusieurs questions que je vois:

  • Le modèle a une fuite « m » qui est important pour les matches de plusieurs lignes en Perl, mais Awk ne pas utiliser des expressions régulières compatibles Perl. (Au moins, awk standard (non-GNU) ne fonctionne pas.)
  • Ignorant que le modèle semble rechercher un « début de l'élément de liste » suivi d'un point d'ancrage « <a> » à « </a> », et non l'élément de la liste finale.
  • Vous recherchez tout ce qui est pas un « > » comme le corps de l'ancre; ce n'est pas automatiquement mal, mais il pourrait être plus habituel de rechercher tout ce qui est pas « < », ou tout ce qui est ni.
  • Awk ne fait pas des recherches multi-ligne.
  • Dans Awk, « $1 » désigne le premier champ, où les champs sont séparés par des caractères de séparation de champ, qui à défaut d'espace blanc.
  • Dans nawk classique (comme indiqué dans le millésime du livre « de sed & awk » 1991) ne dispose pas d'un mécanisme en place pour tirer des sous-champs de matchs, etc.

Il est pas clair que Awk est l'outil idéal pour ce travail. En effet, il est pas tout à fait clair que les expressions régulières sont l'outil pour ce travail.

Je ne sais pas vraiment awk, comment Perl à la place?

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) supprimer les sauts de lignes à partir du fichier, tuyau à travers perl

2) initialiser une variable avec le texte complet, lancer une boucle jusqu'à ce que le texte est parti

3) faire un « non gourmand » match pour la substance délimitée par des balises list-item, enregistrer et imprimer la cible, mis en place pour le passage suivant

sens? (Avertissement, n'a pas essayé ce code moi-même, besoin de rentrer à la maison bientôt ...)

P.S. - "perl -n" est le mode Awk (nawk?). Perl est en grande partie une surcouche de awk, donc je jamais pris la peine d'apprendre awk.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top