使用正则表达式查找和替换


26

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

###############################################################################
# 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 "\1"/g

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

  1. 如何避免搜索\n字符,而是确保#没有出现在搜索组的末尾?
  2. 如何有效使用捕获组?

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

Answers:


18

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

###############################################################################
# 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 "\1"/

模式说明

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

\n\n说,一个空行之后必须发生的利息就行了。如果您不关心前面的空白行,那就^足够了。

#\s\+匹配一个哈希字符,后跟一个或多个空白字符。 \(.*\)捕获该行上的所有后续文本。

替换文字说明

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

然后,插入字符串running,然后插入双引号中括号中捕获的所有内容。


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

1
您可以使用IIRC \r代替换^M行吗?
muru

11

我会用类似的东西:

:s/^#\s\+\(.\{-}\):/running "\1":/
  • ^#匹配#锚定在行首的字符(这将回答问题1)
  • \s\+ 匹配任何空白一次或多次
  • \( 开始一个小组(这回答了问题2)
  • .\{-}\非贪婪的方式匹配任何字符0次或更多次;这与.*尝试匹配的内容越少越好。尝试:在评论中添加一个字符,以了解其重要性
  • \) 结束子组。
  • : 匹配文字 :

然后,我们将其替换为所需的文本,并\1用来指代我们捕获的组。

我用正则表达式测试仪想出了一些东西

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

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

你可以用分组,在那里你必须使用看到这个\(,而不是((这是与POSIX“基本”语法兼容,但与比较常见的POSIX“扩展”的语法或Perl语法)。您可以通过\v在模式中添加标志来控制此操作(请参阅:help /\v详细信息),这将使其与其他应用程序更加兼容,但并不完全兼容(例如,您仍必须.{-}用于非贪婪匹配)

因此,这可以解释为什么几乎(但不是完全)使用“ regex测试器”的原因。

http://www.vimregex.com/作为Vim正则表达式的良好概述/备忘单。


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

8

您可以:

  • 搜索不以结尾结尾的行#:/[^#]$/
  • #\s(.*)在行的开头替换:s/\v^#\s(.*)/running "\1"/

要使用组,您需要:

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

结合起来:

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

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

感谢您明确表示方括号必须转义才能成为regex语法的一部分。正则表达式组在使它们正常工作方面始终遇到问题。
阿达玛
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.