65 votes

vim regex remplacer plusieurs espaces consécutifs par un seul espace

Je travaille souvent avec des fichiers texte qui ont une quantité variable d'espaces comme séparateurs de mots (les traitements de texte comme Word font cela pour répartir équitablement la quantité d'espaces due aux différentes tailles de lettres dans certaines polices et ils mettent cette ennuyeuse quantité variable d'espaces même lors de l'enregistrement en texte brut).

Je voudrais automatiser le processus de remplacement de ces séquences d'espaces blancs de longueur variable par des espaces simples. Je pense qu'une regex pourrait le faire, mais il y a aussi des espaces au début des paragraphes (généralement quatre, mais pas toujours), que je voudrais laisser inchangés. En fait, ma regex ne devrait pas toucher aux espaces de tête, ce qui ajoute à la complexité.

J'utilise vim, donc une regex dans le dialecte de regex de vim me serait très utile, si c'est faisable.

Ma progression actuelle ressemble à ceci :

:%s/ \+/ /g

mais cela ne fonctionne pas correctement.

J'envisage également d'écrire un vim script qui pourrait analyser les lignes de texte une par une, traiter chaque ligne char par char et sauter les espaces après la première, mais j'ai l'impression que ce serait excessif.

112voto

mikerobi Points 10461

Cela remplacera 2 espaces ou plus

s/ \{2,}/ /g

ou vous pouvez ajouter un espace supplémentaire avant le \+ à votre version

s/  \+/ /g

60voto

Aristotle Pagaltzis Points 43253

Cela fera l'affaire :

%s![^ ]\zs  \+! !g

De nombreuses substitutions peuvent être effectuées dans Vim plus facilement qu'avec d'autres dialectes regex en utilisant la fonction \zs y \ze les méta-séquences. Leur rôle est d'exclure une partie de la correspondance du résultat final, soit la partie avant la séquence ( \zs , "s" pour "commencer ici") ou la partie qui suit ( \ze , "e" pour "end here"). Dans ce cas, le motif doit d'abord correspondre à un caractère non espace ( [^ ] ) mais le suivant \zs dit que le résultat final du match (qui est ce qui sera remplacé) commence par après ce personnage.

Comme il n'est pas possible d'avoir un caractère non espace devant un espace de début de ligne, il ne sera pas pris en compte par le motif, et la substitution ne le remplacera pas. C'est simple.

41voto

paxdiablo Points 341644

Dans un souci de pragmatisme, j'ai tendance à le faire en trois étapes :

:g/^    /s//XYZZYPARA/g
:g/ \+/s// /g
:g/^XYZZYPARA/s//    /g

Je ne doute pas qu'il existe une meilleure méthode (peut-être en utilisant des macros ou même une méthode purement regex), mais je trouve généralement que cela fonctionne lorsque je suis pressé. Bien sûr, si vous avez des lignes commençant par XYZZYPARA vous devrez peut-être ajuster la corde :-)

C'est assez bon pour tourner :

    This is a new paragraph
spanning       two lines.
    And    so    is   this but on one line.

dans :

    This is a new paragraph
spanning two lines. 
    And so is this but on one line.

A part : Si vous vous demandez pourquoi j'utilise :g au lieu de :s c'est surtout l'habitude. :g peut tout faire :s peut et bien plus encore. Il s'agit en fait d'un moyen d'exécuter un arbitraire sur les lignes sélectionnées. La commande à exécuter se trouve être s dans ce cas, donc il n'y a pas de réelle différence mais, si vous voulez devenir un vi utilisateur avancé, vous devriez vous pencher sur :g à un moment donné.

7voto

DrAl Points 29528

Il y a beaucoup de bonnes réponses ici (notamment celle d'Aristote : \zs y \ze valent la peine d'être appris). Par souci d'exhaustivité, vous pouvez également procéder de la sorte avec une assertion négative de type look-behind :

:%s/\(^ *\)\@<! \{2,}/ /g

Cela dit "trouvez 2 espaces ou plus ( ' \{2,}' ) qui ne sont PAS précédés par 'le début de la ligne suivi de zéro ou plusieurs espaces'". Si vous préférez réduire le nombre de barres obliques inversées, vous pouvez également procéder ainsi :

:%s/\v(^ *)@<! {2,}/ /g

mais cela ne vous permet d'économiser que deux caractères ! Vous pouvez aussi utiliser ' +' au lieu de ' {2,}' si cela ne vous dérange pas qu'il fasse un tas de changements redondants (par exemple, changer un seul espace en un seul espace).

Vous pouvez également utiliser le look-behind négatif pour ne vérifier que la présence d'un seul caractère non espace :

:%s/\S\@<!\s\+/ /g

qui est à peu près la même chose que (une version légèrement modifiée de celle d'Aristote pour traiter les espaces et les tabulations de la même manière afin d'économiser un peu de frappe) :

:%s/\S\zs \+/ /g

Voir :

:help \zs
:help \ze
:help \@<!
:help zero-width
:help \v

et (lisez tout !) :

:help pattern.txt

2voto

frogstarr78 Points 279

Est-ce que ça marche ?

%s/\([^ ]\)  */\1 /g

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