我有一个带有一堆用户默认值的文件。我想更改一些文本,但是我在努力寻找匹配器和替换器。使用以下示例:

###############################################################################
# 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


我想用# Trackpad: ...替换running "Trackpad: ..."

解决问题,我想出了一些使用一个正则表达式测试器:

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


如果我在Vim中尝试使用它,对我不起作用:

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


我想我的问题可以归结为两个具体问题:


如何避免搜索\n字符,而是确保#不会出现在搜索组?
如何有效使用捕获组?


下面有一些很好的答案。很难在这三者之间进行选择,但是我认为所选的答案对于我的原始规格而言是最准确的。我建议您尝试使用实际文件中的所有三个答案,以了解您的感受。

#1 楼

只是要清楚……我相信您要求这是替换的结果?

###############################################################################
# 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


在这种情况下,我建议使用以下命令:

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

模式的解释

:s/PATTERN/REPLACEMENT/是替代命令。 :%s中的百分号使它适用于整个文件,而不是仅适用于当前行。

\n\n表示关注行必须出现在空白行之后。如果您不关心前面的空白行,那么^就足够了。 #\s\+捕获该行上的所有后续文本。

替换文本的说明

\(.*\)插入行的两端以替换模式中存在的^M^M。否则,文本将移动到空白行之前的行末。要键入每个\n\n,请按Ctrl-V Ctrl-M。

,然后插入字符串^M,然后在双引号内的括号中捕获任何内容。

评论


我无法编辑您的答案,但我相信您的意思是:%s / \ v \ n \ n#\ s +(。*)/ ^ M ^正在运行“ \ 1” /(添加了“ magic”标志)。很难为我的原始问题选择正确的答案,但是我觉得这个答案最接近我的原始预期答案。它也是唯一可在整个文件中使用而无需选择范围的文件。

–squarefrog
2015年4月30日7:31



IIRC您可以使用\ r而不是^ M来获得新行?

–muru
15年4月30日在8:18

#2 楼

我会用类似的东西:

:s/^#\s\+\(.\{-}\):/running "":/




^#匹配锚定在行首的#字符(这回答了问题1)

\s\+一次或多次匹配任何空白

\(发起一个分组(这将回答问题2)

.\{-}\匹配任何字符0或更多次以非贪婪的方式;这与.*不同,因为它尝试匹配的越少越好。尝试在注释中添加一个:字符,以了解为什么这很重要

\)结束该子组。

:匹配文字:


然后将其替换为所需的文本,并使用引用捕获的组。


我使用正则表达式测试器提出了一些建议


正则表达式语法有点像Wiki语法:一堆,它们乍一看都很相似,它们显然都不比其他任何一个都要好,但是有很多区别。

今天,所谓的“ Perl兼容”正则表达式在大多数语言中都是默认设置,但是Vim正则表达式与Perl兼容表达式不兼容!当Perl不在时,Vim regexp语法至少可以追溯到70年代。

您可以在子组中看到这一点,您必须在其中使用\(而不是((这与POSIX“基本”语法,但不包含更常见的POSIX“扩展”语法或Perl语法)。您可以通过在模式中添加\v标志来控制此操作(有关详细信息,请参见:help /\v),这将使其变得“更兼容”,但不能完全兼容(例如,对于非贪婪匹配,您仍必须使用.{-}

因此,这也许可以解释为什么几乎可以使用“ regex测试仪”,但效果不佳。

http://www.vimregex.com/作为Vim regexp的良好概述/备忘单。

评论


很好的答案,尤其是为什么使用正则表达式!=正则表达式。至于您的搜索和替换,由于注释中可能带有或不带有:,所以有些棘手。有关详细信息,请参见完整文件github.com/squarefrog/dotfiles/blob/master/osx/…

–squarefrog
15年4月29日在10:36

#3 楼

您可以:


搜索不以#结尾的行::/[^#]$/

在行首替换#\s(.*)s/\v^#\s(.*)/running ""/


要使用组,您需要:


转义括号,使其成为正则表达式语法的一部分:\(.*\),或者
使用“魔术”通过以\v开头表达式:s/\v...


将其组合:

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


评论


这非常出色,感谢您对标签的含义进行了解释,而不仅仅是我需要编写的文本。

–squarefrog
2015年4月29日在10:21

感谢您明确表示方括号必须转义才能成为regex语法的一部分。正则表达式组在使它们正常工作方面始终遇到问题。

–阿达马
19年8月5日在9:24