compter les chaines uniques correspondant

Le
mpg
Bonjour,

Comment faire, étant donné un fichier texte, pour compter le nombre de
chaînes correspondant à un motif donné, en ne comptant chaque chaîne qu'un
fois même si elle apparaît à plusieurs reprises ? Autrement dit, compter
les chaînes plutôt que leurs occurrences ?

Par exemple, étant donné le « texte » suivant, et le motif \[a-zA-Z@],
j'aimerais avoir un décompte final de 3 (si j'ai bien compté sur mes doigts)

defma@macro#1{defA{#1}}

Pour l'instant, je sais compter les occurrences par exemple avec vim,
et pour compter les chaînes à la place, je verrais bien une ligne de
commande qui termine par | sort --unique | wc, mais le problème est que
chaque chaîne n'apparaît pas isolée sur une ligne.

Un petit coup de pouce serait le bienvenu.

Manuel.
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Stephane Chazelas
Le #755413
2007-06-24, 21:07(+02), mpg:
Bonjour,

Comment faire, étant donné un fichier texte, pour compter le nombre de
chaînes correspondant à un motif donné, en ne comptant chaque chaîne qu'un
fois même si elle apparaît à plusieurs reprises ? Autrement dit, compter
les chaînes plutôt que leurs occurrences ?

Par exemple, étant donné le « texte » suivant, et le motif \[a-zA-Z@],
j'aimerais avoir un décompte final de 3 (si j'ai bien compté sur mes doigts)

#1{defA{#1}}
[...]


perl -le 'print scalar grep {!$s{$_}++}
shift =~ /\[a-zA-Z@]+/g' '#1{defA{#1}}'


--
Stéphane

mpg
Le #755158
Le Sun, 24 Jun 2007 19:25:58 +0000, Stephane Chazelas a écrit:

Par exemple, étant donné le « texte » suivant, et le motif \[a-zA-Z@],
j'aimerais avoir un décompte final de 3 (si j'ai bien compté sur mes
doigts)

#1{defA{#1}}
[...]


perl -le 'print scalar grep {!$s{$_}++}
shift =~ /\[a-zA-Z@]+/g' '#1{defA{#1}}'

Merci, ça marche parfaitement sur cet exemple. Par contre, dès que

j'essaie sur un vrai fichier, il ne tient compte que de ce qui se passe
sur la première ligne.

Vu que je ne connais encore rien à Perl (j'apprendrai bientôt), je me sens
assez incapable de faire la modification, sans doute minime, qui s'impose.
Toujours vu mon ignorance, le !{$s{$_}++} me paraît vraiment magique :
j'adore !

Simple curiosité, il y a moyen de faire la même chose en utilisant
uniquement les outils unix standard ?

Manuel.


Stephane Chazelas
Le #755157
2007-06-24, 22:20(+02), mpg:
Le Sun, 24 Jun 2007 19:25:58 +0000, Stephane Chazelas a écrit:

Par exemple, étant donné le « texte » suivant, et le motif \[a-zA-Z@],
j'aimerais avoir un décompte final de 3 (si j'ai bien compté sur mes
doigts)

#1{defA{#1}}
[...]


perl -le 'print scalar grep {!$s{$_}++}
shift =~ /\[a-zA-Z@]+/g' '#1{defA{#1}}'

Merci, ça marche parfaitement sur cet exemple. Par contre, dès que

j'essaie sur un vrai fichier, il ne tient compte que de ce qui se passe
sur la première ligne.

Vu que je ne connais encore rien à Perl (j'apprendrai bientôt), je me sens
assez incapable de faire la modification, sans doute minime, qui s'impose.
Toujours vu mon ignorance, le !{$s{$_}++} me paraît vraiment magique :
j'adore !


perl -l -0777 -ne 'print scalar grep {!$s{$_}++} /\[a-zA-Z@]+/g
' fichier

Dans:

$s{$_}++

ou plus explicitement

$seen{$_}++

%seen est un tableau associatif.

/\[a-zA-Z]+/g expand to une liste de patterns matchés par cette
regexp (yes, I cause la France, à l'occasion).

grep {code} @list

expand to les elements de @list pour lesquels "code"
expand to "true" (donc, pour lesquel l'element n'a pas ete vu
avant).

scalar @duneline renvoie le nombre d'elements dans une list.


Simple curiosité, il y a moyen de faire la même chose en utilisant
uniquement les outils unix standard ?


Oui, mais c'est plus penible:

< fichier sed 's/\/
&/g' |
sed -n 's/^(\[a-zA-Z@]{1,}).*/1/p' |
sort -u |
wc -l


--
Stéphane



mpg
Le #755156
Le Sun, 24 Jun 2007 20:43:27 +0000, Stephane Chazelas a écrit:

perl -l -0777 -ne 'print scalar grep {!$s{$_}++} /\[a-zA-Z@]+/g
' fichier

Ça fonctionne impec' et c'est ultra-compact. Je sens que je vais adorer

Perl.

[snip explications]


Je lirai ça un peu plus tard, à tête reposée. Merci beaucoup en tout cas,
j'ai une chance de comprendre comme ça au moins :)

Simple curiosité, il y a moyen de faire la même chose en utilisant
uniquement les outils unix standard ?


Oui, mais c'est plus penible:

< fichier sed 's/\/
&/g' |
sed -n 's/^(\[a-zA-Z@]{1,}).*/1/p' | sort -u | wc -l

C'est moins élégant en effet. Bon à savoir quand même : je ne pense jamais

à sed.

Manuel.


Publicité
Poster une réponse
Anonyme