2010-10-27 4 views
8

J'ai un tableau comme celui-ciL'opérateur de substitution Per Perl peut-il faire correspondre un élément dans un tableau?

my @stopWords = ("and","this",....) 

Mon texte est dans cette variable

my $wholeText = "....and so this is...." 

Je veux faire correspondre chaque occurrence de chaque élément de mon tableau des mots vides dans le scalaire wholeText et de le remplacer par des espaces .

Une façon de faire est la suivante:

foreach my $stopW (@stopWords) 
{ 
    $wholeText =~ s/$stopW/ /; 
} 

Cela fonctionne et remplace toutes les occurrences de tous les mots d'arrêt. Je me demandais simplement s'il y avait une façon plus courte de le faire.

Comme ceci:

$wholeText =~ s/@stopWords/ /; 

Ce qui précède semble pas fonctionner bien.

Répondre

-1
grep{$wholeText =~ s/\b$_\b/ /g}@stopWords; 
+0

Cela supprime le 'et' dans 'mille'. –

+0

@Jonathan Leffler: merci de m'avoir signalé, mais je pense que OP ne s'occupe pas non plus de ce cas. :) –

+1

L'OP veut probablement le traiter; il veut probablement supprimer toutes les occurrences de chaque mot d'arrêt (isolément), pas seulement la première occurrence de chaque mot. Une solution complète le fait tout à la fois. –

3

Qu'en est-:

my $qrstring = '\b(' . (join '|', @stopWords) . ')\b'; 
my $qr = qr/$qrstring/; 
$wholeText =~ s/$qr/ /g; 

Concaténer tous les mots pour former '\b(and|the|it|...)\b'; les parenthèses autour de la jointure sont nécessaires pour lui donner un contexte de liste; sans eux, vous vous retrouvez avec le compte du nombre de mots). Les métacaractères '\b' marquent les limites des mots et vous empêchent donc de changer 'mille' en 'thous'. Convertir cela en une expression régulière entre guillemets; appliquez-le globalement à votre chaîne de sujet (de sorte que toutes les occurrences de tous les mots d'arrêt soient supprimées en une seule opération).

Vous pouvez également faire sans la variable « $qr « :

my $qrstring = '\b(' . (join '|', @stopWords) . ')\b'; 
$wholeText =~ s/$qrstring/ /g; 

Je ne pense pas que je me soucie de maintenir le code de toute personne qui a réussi à faire sans la variable » $qrstring »; cela peut probablement être fait, mais je ne pense pas que ce serait très lisible.

+0

Merci pour toutes les réponses. J'ai essayé le code de Nikhil Jain et ça marche. Merci aux autres aussi. U tout le rock! Merci! – Radz

5

Ma meilleure solution:

$wholeText =~ s/$_//g for @stopWords; 

Vous pouvez affiner l'expression rationnelle en utilisant certains \b et des espaces.

3

Ma version paranoïaque:

$wholeText =~ s/\b\Q$_\E\b/ /gi for @stopWords; 

Utilisez \b pour correspondre à des limites de mots, et \Q..\E juste au cas où l'un de vos mots vides contient des caractères qui peuvent être interprétés comme « spécial » par le moteur de regex.

3

Vous pouvez envisager d'utiliser une jointure regex pour créer une seule regex.

my $regex_str = join '|', map { quotemeta } @stopwords; 
$string =~ /$regex_str/ /g; 

Notez que la partie quotemeta fait juste en sorte que tous les caractères sont correctement saisies regex.

7

Alors que les différents map/for solutions à base de travail sera , ils vont aussi faire le traitement regex de votre chaîne séparément pour chaque mot vide. Bien que cela ne soit pas un gros problème dans l'exemple donné, cela peut entraîner des problèmes de performances majeurs à mesure que le texte cible et la liste des mots vides augmentent. Jonathan Leffler et Robert P sont sur la bonne voie avec leurs suggestions de fusionner tous les mots d'arrêt ensemble dans une seule regex, mais un simple join de tous les mots vides dans une seule alternance est une approche grossière et, encore une fois, devient inefficace si la liste des mots vides est longue.

Entrez Regexp::Assemble, qui vous construire beaucoup plus « intelligent » regex pour gérer tous les matches à la fois - je l'ai utilisé à bon escient avec des listes allant jusqu'à 1700 ou si les mots à vérifier contre:

#!/usr/bin/env perl 

use strict; 
use warnings; 
use 5.010; 

use Regexp::Assemble; 

my @stopwords = qw(and the this that a an in to); 

my $whole_text = <<EOT; 
Fourscore and seven years ago our fathers brought forth 
on this continent a new nation, conceived in liberty, and 
dedicated to the proposition that all men are created equal. 
EOT 

my $ra = Regexp::Assemble->new(anchor_word_begin => 1, anchor_word_end => 1); 
$ra->add(@stopwords); 
say $ra->as_string; 

say '---'; 

my $re = $ra->re; 
$whole_text =~ s/$re//g; 
say $whole_text; 

qui sort:

\b(?:t(?:h(?:at|is|e)|o)|a(?:nd?)?|in)\b 
--- 
Fourscore seven years ago our fathers brought forth 
on continent new nation, conceived liberty, 
dedicated proposition all men are created equal. 
Questions connexes