Najít a nahradit pomocí regulárních výrazů

Mám soubor se spoustou výchozích nastavení uživatelů. Chci změnit část textu, ale bojuji přijít s porovnávačem a náhradníkem. Pomocí následujícího příkladu:

############################################################################### # Trackpad, mouse, keyboard, Bluetooth accessories, and input # ############################################################################### # Trackpad: enable tap to click for this user and for the login screen defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true 

Chtěl bych nahradit # Trackpad: ... s running "Trackpad: ..."

Když jsem problém prolomil, přišel jsem s něčím pomocí testeru regex:

/\n\n#\s(.*)/g 

Pokud se to pokusím použít ve Vimu, nefunguje mi to:

:/\n\n#\s(.*)/running "\1"/g 

Myslím, že můj problém spadá do dvou konkrétních otázek:

  1. Jak se mohu vyhnout hledání \n znaků a místo toho se ujistit, že se # nezobrazí na konci vyhledávací skupiny?
  2. Jak mohu efektivně využívat skupiny zachycení?

Níže uvádíme některé skvělé odpovědi. Těžko si vybrat mezi všemi třemi, ale mám pocit, že zvolená odpověď je pro moji původní specifikaci nejpřesnější. Doporučuji vám vyzkoušet všechny tři odpovědi se skutečným souborem , abyste zjistili, jak se k nim cítíte.

Odpověď

Aby bylo jasno … Věřím, že jste požádali, aby to bylo výsledkem substituce?

############################################################################### # Trackpad, mouse, keyboard, Bluetooth accessories, and input # ############################################################################### running "Trackpad: enable tap to click for this user and for the login screen" defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true 

V takovém případě doporučuji následující příkaz:

:%s/\n\n#\s\+\(.*\)/^M^Mrunning "\1"/

Vysvětlení vzoru

:s/PATTERN/REPLACEMENT/ je náhradní příkaz. Přihlašovací procento :%s umožňuje pracovat na celém souboru, nikoli pouze na aktuálním řádku.

\n\n říká, že k zájmové linii musí dojít za prázdným řádkem. Pokud jste se nestarali o předchozí prázdný řádek, pak by ^ stačilo.

#\s\+ odpovídá hash znak následovaný jedním nebo více mezerami. \(.*\) zachycuje veškerý následující text na řádku.

Vysvětlení náhradního textu

^M^M vloží dva konce řádků, které nahradí \n\n přítomné ve vzoru. Jinak by se text přesunul na konec řádku před prázdný řádek. Chcete-li zadat každý ^M, stiskněte Ctrl-V Ctrl-M .

Poté vložte řetězec running a za ním vše, co bylo v závorkách zachyceno v uvozovkách.

Komentáře

  • Nemohu upravit vaši odpověď, ale domnívám se, že jste mysleli :%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/ (přidáno “ kouzlo “ vlajka). Je opravdu těžké vybrat správná odpověď na mou původní otázku, ale mám pocit, že tato odpověď je nejblíže mé původní očekávané odpovědi. Je také jediný, který funguje v celém souboru bez nutnosti výběru rozsahu.
  • IIRC můžete použít \r místo ^M získat nové řádky?

Odpovědět

Použil bych něco jako:

:s/^#\s\+\(.\{-}\):/running "\1":/ 
  • ^# tak, aby odpovídal # ukotvenému znaku na začátku řádku (odpovídá na otázku 1)
  • \s\+ tak, aby odpovídal libovolnému mezerám jednou nebo vícekrát
  • \( k založení skupiny (odpovídá na otázku 2)
  • .\{-}\ k přiřazení libovolného znaku 0 nebo vícekrát v nenásytný způsob ; toto je odlišné od .* v tom, že se snaží odpovídat co nejméně a ne co nejvíce. Zkuste přidat do komentáře znak :, abyste zjistili, proč je to důležité
  • \) k ukončení podskupiny.
  • : odpovídá doslovnému :

Toto potom nahradíme textem chcete a pomocí \1 odkázat na skupinu, kterou jsme zajali.

Něco jsem vymyslel pomocí tester regexu

Syntaxe regulárního výrazu je něco jako syntaxe wiki: je jich spousta, všechny na první pohled vypadají podobně, žádný je zjevně lepší než kterýkoli jiný, ale existuje mnoho rozdílů.

Dnes jsou de facto výchozí takzvané „Perl kompatibilní“ regulární výrazy ve většině jazyků, ale regulární výrazy Vim nejsou kompatibilní s výrazy kompatibilními s Perlem! Syntaxe vim regexp sahá přinejmenším do 70. let, kdy Perl ještě nebyl.

Vidíte to u podskupin, kde musíte použít \( a ne ( (to je kompatibilní se základní „syntaxí“ POSIX, ale ne s běžnější POSIX „rozšířenou“ syntaxí nebo syntaxí Perlu).Toto můžete ovládat přidáním příznaku \v do vzoru (viz :help /\v pro podrobnosti), díky tomu bude „kompatibilnější“, ale ne úplně (stále musíte použít .{-} například pro nenáročné zápasy)

Takže to by mohlo vysvětlovat, proč použití „testovacího nástroje regulárního výrazu“ téměř, ale ne zcela, funguje.

http://www.vimregex.com/ jako dobrý přehled / cheatsheet Vim regexps.

Komentáře

  • Skvělá odpověď, zejména s důvodem proč regex! = regex. Pokud jde o hledání a nahrazování, je ‚ trochu složité, protože komentář může nebo nemusí mít :. Podrobnosti najdete v úplném souboru github.com/squarefrog/dotfiles/blob/master/osx/…

Odpovědět

Můžete:

  • hledat řádky, které nekončí v #: :/[^#]$/
  • nahradit #\s(.*) na začátku řádek: s/\v^#\s(.*)/running "\1"/

Chcete-li použít skupiny, musíte buď:

  • uniknout z hranatých závorek, aby stávají se součástí syntaxe regexu: \(.*\) nebo
  • používají „magic“ od začátek výrazu \v: s/\v...

Kombinace:

:/[^#]$/s/\v^#\s(.*)/running "\1"/ 

Komentáře

  • Funguje to skvěle, díky za zahrnutí vysvětlení toho, co značky znamenají, nikoli jen textu, který jsem potřeboval napište.
  • Děkujeme za objasnění, že závorky mají t o uniknout, aby se stal součástí syntaxe regulárního výrazu. Vždy jsem měl problém s regexovými skupinami, když jsem je přiměl pracovat.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *