2009-06-01 4 views
3

J'essaye de faire la recherche et le remplacement en utilisant une regex en Perl.Comment puis-je ajouter au lieu de remplacer du texte lors d'une recherche et de remplacer avec Perl?

Le texte que je cherche est:

<space>Number<space>NumberNumberNumber 

et je veux le remplacer par:

<space>Number<space>NumberNumberNumberI 

je l'expression rationnelle suivante qui travaille à trouver la chaîne:

\s[0-9]\s[0-9[0-9][0-9] 

Mais que dois-je faire pour remplacer la chaîne? Fondamentalement, je veux juste ajouter un «je» à la fin.

J'utilise:

perl -pi -e "s/\s[0-9]\s[0-9][0-9][0-9]/I/;" testFile 

mais cela remplace le tout avec moi plutôt que annexant à lui.

Répondre

9

C'est ce que les références sont pour. Entourez simplement la section de texte que vous voulez capturer avec des parenthèses. Le premier ensemble de parenthèses est disponible en $ 1, le deuxième en $ 2, et ainsi de suite.

s/(\s[0-9]\s[0-9]{3})/$1I/ 

Avec Perl 5.10 nous avons gagné named captures, afin que vous puissiez dire

s/(?<bodytext>\s[0-9]\s[0-9]{3})/$+{bodytext}I/ 

Le < et inbetween choses > est le nom. Les noms deviennent des clés dans la variable %+ et les valeurs sont le texte capturé.

Une autre solution consiste à utiliser un zero-width positive look-behinds

s/(?<=\s[0-9]\s[0-9]{3})/I/ 

ou son, nouveau à Perl 5.10, raccourci \K

s/\s[0-9]\s[0-9]{3}\K/I/ 

Essayez

perl -pi -e 's/(\s[0-9]\s[0-9][0-9][0-9])/$1I/' filename 

Si vous utilisez doub le guillemet le $ 1 est interpolé par le shell avant que Perl le voit. Si vous avez des problèmes avec quelque chose qui, selon vous, devrait fonctionner, il peut être utile de regarder ce que Perl voit. Vous pouvez le faire avec B::Deparse:

perl -MO=Deparse -pi -e "s/(\s[0-9]\s[0-9][0-9][0-9])/$1I/" filename 

qui produira la sortie suivante.

BEGIN { $^I = ""; } 
LINE: while (defined($_ = <ARGV>)) { 
    s/(\s[0-9]\s[0-9][0-9][0-9])/I/; 
} 
continue { 
    print $_; 
} 
-e syntax OK 

De cela, nous pouvons voir que $1 manque.Permet de réessayer avec des guillemets simples:

perl -MO=Deparse -pi -e 's/(\s[0-9]\s[0-9][0-9][0-9])/$1I/' filename 
BEGIN { $^I = ""; } 
LINE: while (defined($_ = <ARGV>)) { 
    s/(\s[0-9]\s[0-9][0-9][0-9])/$1I/; 
} 
continue { 
    print $_; 
} 
-e syntax OK 

Et une fois à l'échappement:

perl -MO=Deparse -pi -e "s/(\s[0-9]\s[0-9][0-9][0-9])/\$1I/" filename 
BEGIN { $^I = ""; } 
LINE: while (defined($_ = <ARGV>)) { 
    s/(\s[0-9]\s[0-9][0-9][0-9])/$1I/; 
} 
continue { 
    print $_; 
} 
-e syntax OK 
+0

qui est toujours en remplaçant le tout avec I :( –

+0

Avez-vous ajouté les parens? –

+0

ouais c'est ma commande complète perl -pi -e "s/(\ s [0-9] \ s [0-9] [0-9] [0-9])/$ 1I /" testFichier.phy –

0

Une version plus courte de la réponse à partir de 2009 - vous pouvez utiliser zéro largeur affirmation de lookbehind positif, (?<=pattern) , ou \K, pour insérer quelque chose après votre match:

%echo "test" | perl -p -e "s/(?<=test)/ing/" 
testing 
%echo "test" | perl -p -e "s/test\K/ing/" 
testing 
% 

Vous pouvez également insérer quelque chose avant votre match, vous utiliseriez zéro largeur assertion avant positive, (?=pattern):

%echo "test" | perl -p -e "s/(?=test)/#/" 
#test 
% 

Référence:

Questions connexes