Regex om ruimte in te voegen in vim

Ik ben een regex supernoob (ik lees alleen mijn eerste artikelen over hen) en werk tegelijkertijd aan een sterker gebruik van vim. Ik wil een regex gebruiken om naar alle exemplaren van een dubbele punt : te zoeken die niet worden gevolgd door een spatie en invoegen één spatie tussen die dubbele punten en elk teken achter hen.

Als ik begin met:

foo:bar

Ik zou graag willen eindigen met

foo: bar

Ik heb zo veel gekregen als % s /: [a-z] maar nu weet ik niet wat ik moet doen voor het volgende deel van de instructie % s .

Ook, hoe verander ik de : [a-z] -instructie om te zorgen dat alles wat geen spatie is wordt gevangen?

14
Een truc die ik heb gevonden voor het ontwikkelen van mijn regex-uitdrukkingen is het gebruik van / om de zoekterm te bouwen en ervoor te zorgen dat deze exact overeenkomt met wat ik wil en vervolgens de vervangende tekst met een lege zoekterm uit te voeren. In VIM vervangt% s//bar/g de vorige zoekterm door bar. Dit heeft het voor mij veel gemakkelijker gemaakt om te onderzoeken wat er mogelijk is voor mijn zoekterm zonder dat ik de zoekterm in het midden van mijn vervangopdracht moet kopiëren.
toegevoegd de auteur Sam Brinck, de bron
@ De truc van SamBrinck is vooral handig als je de optie 'incsearch' hebt ingesteld, omdat de tekst die overeenkomt met de zoekopdracht is gemarkeerd terwijl je typt. Dat maakt het heel gemakkelijk om met het patroon te friemelen en onmiddellijk de resultaten te zien.
toegevoegd de auteur jamessan, de bron

4 antwoord

:% s /: \ (\ S \) /: \ 1/g

\S matches any character that is not whitespace, but you need to remember what that non-whitespace character is. This is what the \(\) does. You can then refer to it using \1 in the replacement.

U koppelt dus een : , een niet-witruimteteken en vervangt het door een : , een spatie en het vastgelegde teken.


Dit wijzigen om de tekst alleen te wijzigen als er maar één : is, is vrij eenvoudig. Zoals anderen hebben gesuggereerd, zal het gebruik van enkele van de zero-width-beweringen nuttig zijn.

:%s/:\@!<:[^:[:space:]]\@=/: /g

  • :\@!< matches any non-:, including the start of the line. This is an important characteristic of the negative lookahead/lookbehind assertions. It's not requiring that there actually be a character, just that there isn't a :.

  • : matches the required colon.

  • [^:[:space:]] introduces a couple more regex concepts.

    • The outer [] is a collection. A collection is used to match any of the characters listed inside. However, a leading ^ negates that match. So, [abc123] will match a, b, c, 1, 2, or 3, but [^abc123] matches anything but those characters.

    • [:space:] is a character class. Character classes can only be used inside a collection. [:space:] means, unsurprisingly, any whitespace. In most implementations, it relates directly to the result of the C library's isspace function.

    Tying that all together, the collection means "match any character that is not a : or whitespace".

  • \@= is the positive lookahead assertion. It applies to the previous atom (in this case the collection) and means that the collection is required for the pattern to be a successful match, but will not be part of the text that is replaced.

Dus wanneer het patroon overeenkomt, vervangen we de : door zichzelf en een spatie.

22
toegevoegd
% s/[^:] \ zs: \ ze [^:] /:/g komt overeen met slechts één dubbele punt gevolgd door iets anders dan een spatie (of dubbele punt)
toegevoegd de auteur Sam Brinck, de bron
Dit is waar ik naar op zoek was. Hoewel mijn specifieke geval geen dubbele dubbele punten had, zou het een leuke toevoeging zijn voor het antwoord als het gemakkelijk genoeg voor u is. Bedankt voor de hulp :)
toegevoegd de auteur Lee Quarella, de bron
Dan heeft de vraag verduidelijking nodig. Alles wat werd vermeld was een dubbele punt gevolgd door een niet-spatie spatie moet een spatie ingevoegd tussen de dubbele punt en de volgende niet-spatie tekens.
toegevoegd de auteur jamessan, de bron
Dit werkt echter alleen op de eerste reeks dubbele punten: probeer het op "een :: voorbeeld". Dat is al dan niet geschikt voor de doeleinden van @ Lee.
toegevoegd de auteur Matt Parker, de bron

Een interessante eigenschap van Vim regex is de aanwezigheid van \ zs en \ ze . Andere motoren hebben ze ook, maar ze zijn niet erg gebruikelijk.

Het doel van \ zs is om het begin van de overeenkomst te markeren en \ ze aan het einde ervan. Bijvoorbeeld:

ab\zsc

komt overeen met c , alleen als je eerder ab hebt. Op dezelfde manier:

a\zebc

komt overeen met a alleen als u achter de code bc zit. Je kunt beide combineren:

a\zsb\zec

komt overeen met b alleen indien tussen a en c . Je kunt ook overeenkomsten met een nulbreedte maken, wat ideaal is voor wat je probeert te doen:

:%s/:\zs\ze\S/ /

Uw zoekopdracht heeft geen grootte, alleen een positie. En jij vervangt die positie door "". Overigens betekent \ S elk teken, behalve witruimte.

:\zs\ze\S matches the position between a colon and something not a space.

7
toegevoegd
\ zs en \ ze zijn in essentie snelkoppelingen voor respectievelijk positieve kijk op het uiterlijk en lookahead-beweringen. \ zs is hetzelfde als \% (patroon voor zs \) \ @ <= en \ ze is hetzelfde als \ % (patroon na ze \) \ @ = is hetzelfde als \ ze . Dus, hoewel het overdreven breed is voor dit eenvoudige voorbeeld, zou je ook :% s/\% (: \) \ @ <= \% (\ S \) \ @ =// g kunnen gebruiken.
toegevoegd de auteur jamessan, de bron

U wilt een nul-brede negatieve lookahead-bewering gebruiken, wat een mooie manier is om te zeggen dat u zoekt naar een personage dat geen spatie is, maar het niet in de wedstrijd opneemt:

:%s/: \@!/: /g

De \ @! is de negatieve lookahead.

7
toegevoegd
De basis voor Vim's regex komt van vi, die van ex komt, die uit ed komt en al lang vóór PCRE bestond (wat de meeste mensen denken als "standaard" regex, hoewel er niet zoiets bestaat). Echt, het zijn de andere regex-syntaxis die zo verschillend zijn. ;)
toegevoegd de auteur jamessan, de bron
Ik heb nooit begrepen waarom ik een zo verschillende regex-sintax in VIM heb gebruikt, is het ding dat ik het meeste haat van VIM (wat trouwens mijn favoriete editor is).
toegevoegd de auteur curial, de bron

je wilt waarschijnlijk : [^] gebruiken om alles behalve spaties te bewerken. Zoals vermeld door Matt zal dit ervoor zorgen dat je vervanger het extra karakter vervangt.
Er zijn verschillende manieren om dit te vermijden, hier zijn er 2 die ik handig vind.
1) Omring het laatste deel van de zoekterm met haakjes \ (\) , hiermee kunt u verwijzen naar dat deel van de zoekopdracht in uw vervangende term met een /1 .
Je definitieve vervangstring zou er als volgt uit moeten zien:

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

2) beëindig de zoekterm vroeg met \ ze Dit betekent dat voor een overeenkomst aan de volledige zoekterm moet worden voldaan, maar alleen het gedeelte vóór \ ze wordt gehighlighted/of vervangen door Je definitieve vervangstring zou er als volgt uit moeten zien:

%s/:\ze[^ ]/: /g
4
toegevoegd