2010-08-11 5 views
0

donné Par souci de simplicité, disons que nous avons des chaînes d'entrée avec ce format:Regex pour remplacer tous les ocurrences d'un caractère donné, seulement après un match

*text1*|*text2* 

Alors, je veux partir text1 seul, et supprimer tous les espaces dans text2.

Cela pourrait être facile si nous ne disposions pas text1, une recherche simple et remplaçons comme celui-ci ferait:

%s/\s//g 

mais dans ce contexte, je ne sais pas quoi faire.

J'ai essayé avec quelque chose comme:

%s/\(.*|\S*\).\(.*\)/\1\2/g 

qui fonctionne, mais en supprimant seul le premier caractère, je veux dire, cela devrait être exécuté sur la même ligne une fois pour chaque espace incriminée.

Donc, une restriction préférée, est à résoudre cela avec une seule recherche et remplacer. Et, bien que j'aie utilisé la syntaxe de Vim, utilisez la saveur d'expression régulière avec laquelle vous êtes le plus à l'aise pour répondre, je veux dire, peut-être que vous avez besoin de fonctionnalités offertes uniquement par Perl.

Edit: Ma solution pour VIM:

%s:\(|.*\)\@<=\s::g 
+0

'awk' peut résoudre ce problème pour vous en un rien de temps. –

+0

Vous voulez dire, d'abord analyser la "colonne" à travers awk, puis en utilisant sed ou quoi que ce soit pour lancer la recherche et remplacer dans cette seule colonne? C'est similaire à ma solution actuelle, mais je voudrais le faire uniquement avec l'expression rationnelle. – Doppelganger

+2

@Carl Norum: J'ai installé awk, mais il se trouve juste là et ne fait rien. Ou vouliez-vous dire un programme awk? :) – ysth

Répondre

3

Une façon, en Perl:

s/(^.*\||(?=\s))\s*/$1/g 

Certes, une plus grande efficacité est possible si vous permettez plus d'une recherche et de remplacement .

+0

Je suis en train de lire cette réponse à une question similaire que je n'ai trouvée qu'après avoir demandé la mienne. http://stackoverflow.com/questions/608319/regex-replace-but-only-between-two-patterns La réponse acceptée utilise lookaround, alors peut-être que le vôtre est similaire. Je n'ai pas encore trouvé de solution, alors j'essaierai de comprendre votre solution et de voir si cela fonctionne. – Doppelganger

+0

@Doppelganger: Le lookaround n'est pas vraiment nécessaire dans le mien; 's/(^. * \ ||) \ s */$ 1/g' devrait fonctionner aussi bien. Je pensais que le lookforward le rendrait plus rapide, mais je ne sais pas si c'est vrai. – ysth

+0

J'ai trouvé ma solution avec lookaround, mais j'essaie toujours de comprendre la vôtre. Je n'ai pas cet atome (^. * \ ||), je l'obtiens comme n'importe quoi depuis le début de la ligne jusqu'à un tuyau, mais je ne comprends pas à quoi sert le second tuyau. – Doppelganger

3

Vous avez donc une chaîne avec un tube (|) et vous ne souhaitez remplacer que les espaces qui ne précèdent pas le tube?

s/\s+(?![^|]*\|)//g 
+0

Mieux que le mien. Ou 's/\ s + (?!. *? \ |) // gs' – ysth

0

Vous pouvez essayer l'insertion de code Perl dans une expression régulière (en utilisant la syntaxe (?{...})), qui est cependant plutôt une fonctionnalité expérimentale et pourrait ne pas fonctionner ou être encore disponibles dans votre scénario.

Ce

s/(.*?\|)(.*)(?{ $x = $2; $x =~ s:\s::g })/$1$x/ 

devrait fonctionner en théorie, mais je suis un "Mémoire insuffisante!" échec, qui peut être corrigé en remplaçant '\ s' par un espace:

s/(.*?\|)(.*)(?{ $x = $2; $x =~ s: ::g })/$1$x/ 
+0

Si vous faites plusieurs substitutions, vous pouvez aussi faire' s/(\ |. *)/(My $ x = $ 1) = ~ s! \ s !! g; $ x/se'; non '(? {...})' nécessaire. – ysth