2 votes

Comment extraire des mots de plus de 2 caractères d'une chaîne de caractères en perl ?

Je suppose qu'une sorte d'expression rationnelle serait utilisée à cette fin ?

Je dois faire en sorte que chaque mot soit composé de deux caractères ou plus, qu'il commence par une lettre et que les autres caractères soient des lettres, des chiffres et des traits de soulignement.

Voici le code que j'ai actuellement, bien qu'il ne soit pas très proche du résultat que je souhaite obtenir :

while (my $line=<>) {
  # remove leading and trailing whitespace
  $line =~ s/^\s+|\s+$//g;
  $line = lc $line;
  @array = split / /, $line;
  foreach my $a (@array){
    $a =~ s/[\$#@~!&*()\[\];.,:?^ `\\\/]+//g;
    push(@list, "$a");
  }
}

Un exemple d'entrée serait :

#!/usr/bin/perl -w
use strict;
# This line will print a hello world line.
print "Hello world!\n";
exit 0;

Et le résultat souhaité serait (par ordre alphabétique) :

bin
exit 
hello
hello
line
perl
print
print
strict
this
use
usr
will
world

3voto

zdim Points 29788
my @matches = $string =~ /\b([a-z][a-z0-9_]+)/ig;

Si l'opération insensible à la casse ne doit être appliquée qu'à un sous-modèle, peut-on l'intégrer

/... \b((?i)[a-z][a-z0-9_]+) .../

(ou, il peut être désactivé après le sous-modèle, (?i)pattern(?-i) )

Ce [a-zA-Z0-9_] va comme \w , a " caractère des mots "si c'est effectivement ce qu'il faut.

La regex ci-dessus sélectionne les mots comme il se doit sans qu'il soit nécessaire de couper la ligne sur un espace, ce qui est fait dans le programme illustré. On peut l'appliquer à la ligne entière (ou au texte entier), peut-être après avoir supprimé les divers caractères spéciaux. †

Il y a une question d'autres cas - pourquoi pas des traits d'union ? Des apostrophes ? Le tilde ? On ne les trouve pas dans les identificateurs, alors que le système semble destiné à traiter du texte de programmation, mais des commentaires sont inclus ; quels autres caractères légitimes peuvent-ils exister ?


Note sur divisé -sur les espaces blancs

L'exposition split / /, $line se divise exactement sur cet espace. Le mieux est split /\s+/, $line -- ou, mieux encore, d'utiliser split Le modèle spécial de l'entreprise split ' ', $line : divisé sur un nombre quelconque d'espaces blancs consécutifs, et où les espaces de début et de fin sont éliminés.


† L'exemple montré est correctement traité comme souhaité par la seule regex donnée.

use strict;
use warnings;
use feature 'say';
use Path::Tiny qw(path);  # convenience, to slurp the file

my $fn = shift // die "Usage: $0 filename\n";

my @matches = sort map { lc } 
    path($fn)->slurp =~ /\b([a-z][a-z0-9_]+)/ig; 

say for @matches;

J'ai ajouté le tri et la mise en minuscule pour correspondre à l'exemple de code dans la question, mais tout le traitement est effectué avec la regex indiquée sur le contenu du fichier dans une chaîne.

Le résultat est tel que souhaité (sauf que line y world ici viennent deux fois, ce qui est correct).

Notez que lc peut être appliqué sur la chaîne de caractères avec le contenu du fichier, qui est ensuite traité avec la regex, ce qui est plus efficace. Bien que ce ne soit en principe pas la même chose dans ce cas, cela peut être

perl -MPath::Tiny -wE'$f = shift // die "Need filename\n"; 
    @m = sort lc(path($f)->slurp) =~ /\b([a-z]\w+)/ig; 
    say for @m'

Ici, j'ai utilisé \w . Ajustez le caractère réel pour qu'il corresponde, s'il est différent.

2voto

TLP Points 48922

Curieusement, cela peut être fait avec l'une de ces longues phrases typiques de Perl.

$ perl -lwe'print for sort grep /^\pL/ && length > 1, map { split /\W+/ } map lc, <>' a.txt
bin
exit
hello
hello
line
line
perl
print
print
strict
this
use
usr
will
world
world

Faisons le tour de la question et voyons ce que nous pouvons apprendre. Cette ligne se lit de droite à gauche.

  • a.txt est le fichier d'arguments à lire
  • <> est l'opérateur diamant, qui lit les lignes du fichier. Comme il s'agit d'un contexte de liste, il épuisera le gestionnaire de fichier et retournera toutes les lignes.
  • map lc , abréviation de map { lc($_) } appliquera le lc sur toutes les lignes et retourner le résultat.
  • map { split /\W+/ } est une opération polyvalente. Elle supprime les caractères indésirables (les caractères de non-mots), et divise également la ligne à cet endroit, et renvoie une liste de tous ces mots.
  • grep /^\pL/ && length > 1 trie les chaînes de caractères qui commencent par une lettre \pL et sont plus longues que 1 et les retourne.
  • sort trie par ordre alphabétique la liste entrant par la droite et la renvoie par la gauche
  • for est une boucle for, appliquée à la liste entrante, dans le style post-fixe.
  • print est le diminutif de print $_ et il s'imprimera une fois pour chaque élément de la liste dans la boucle for.
  • En -l dans la commande perl va "fixer" les fins de ligne pour nous (les supprimer en entrée, les ajouter en sortie). Cela rendra l'impression plus jolie à la fin.

Je ne dirai pas que vous obtiendrez un résultat parfait, mais vous devriez être en mesure d'acquérir certaines techniques pour terminer votre propre programme.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X