J'ai un fichier qui ressemble à quelque chose comme ça:
<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>
J'ai besoin d'extraire quoi que ce soit entre les guillemets qui suivent name=
, i.e., content_analyzer
, content_analyzer2
et content_analyzer_items
.
Je le fais sur une machine Linux, donc une solution utilisant sed, Perl, grep ou bash convient parfaitement.
Etant donné que vous devez faire correspondre le contenu sans l'inclure dans le résultat (doit Correspondre à name="
mais ne fait pas partie du résultat souhaité), une forme de Une correspondance de largeur nulle ou une capture de groupe est requise. Cela peut être fait facilement avec les outils suivants:
Avec Perl, vous pouvez utiliser l’option n
pour boucler ligne par ligne et imprimer Le contenu d’un groupe de capture s’il correspond:
Perl -ne 'print "$1\n" if /name="(.*?)"/' filename
Si vous avez une version améliorée de grep, telle que GNU grep, il est possible que L'option -P
soit disponible. Cette option activera les expressions rationnelles de type Perl, , Vous permettant d'utiliser \K
, qui est un raccourci. Cela réinitialisera La position de la correspondance, donc tout ce qui la précède a une largeur nulle.
grep -Po 'name="\K.*?(?=")' filename
L’option o
permet à grep d’imprimer uniquement le texte correspondant, au lieu de la ligne entière
Une autre méthode consiste à utiliser directement un éditeur de texte. Avec Vim, l’une des manières De procéder serait de supprimer des lignes sans name=
et d’extraire ensuite le contenu des lignes résultantes:
:v/name=/d
:%s/\v.*name\="([^"]+)".*/\1
Si, pour une raison quelconque, vous n’avez pas accès à ces outils, un résultat similaire pourrait être obtenu avec grep standard. Cependant, sans le look Autour, il faudra nettoyer plus tard:
grep -o 'name="[^"]*"' filename
Dans toutes les commandes ci-dessus, les résultats seront envoyés à stdout
. Il est important de se rappeler que vous pouvez toujours les sauvegarder en le connectant à un fichier En ajoutant:
> result
à la fin de la commande.
Si vous utilisez Perl, téléchargez un module pour analyser le XML: XML :: Simple , XML :: Twig ou XML :: LibXML . Ne réinventez pas la roue.
L'expression régulière serait:
.+name="([^"]+)"
Ensuite, le regroupement serait dans le\1
Un analyseur HTML devrait être utilisé à cette fin plutôt que des expressions régulières. Un programme Perl qui utilise HTML::TreeBuilder
:
#!/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>
content_analyzer
content_analyzer2
content_analyzer_items
Voici une solution utilisant HTML nettoie & 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' -n
cela pourrait le faire:
Perl -ne 'if(m/name="(.*?)"/){ print $1 . "\n"; }'
Oups, la commande sed doit précéder la commande bien rangée:
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' -n
Si la structure de votre XML (ou du texte en général) est corrigée, le moyen le plus simple consiste à utiliser cut
. Pour votre cas particulier:
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 '"'