regex - 使用 vim 替换出现次数可变的不匹配字符串

标签 regex vim replace

我希望使用 vim 从包含以下示例文本的文件中仅提取方括号和里面的数字:

13_[4]_3_[4]_[1]_5_[1]_29_[3]_4_[2]_9_[1]_6_[2]_4
14_[4]_28_[3]_4_[2]_12_[1]_8_[2]_2
[1]_[4]_15_[1]_16_[3]_4_[2]_11_[1]_16_[2]_2
9_[4]_3_[4]_3_[4]_9_[4]_4_[4]_7_[1]_12_[3]_4_[2]_9_[1]_[2]_2
14_[4]_30_[3]_4_[2]_5_[1]_19_[1]_3_[1]_8_[2]_10_[1]_4_[1]_3_[1]_2

因此,对于第一个示例行,我想要一个如下所示的输出行:
[4][4][1][1][3][2][1][2]。

我可以轻松删除方括号:
:%s/\[\d\]//g

但是我在尝试删除所有与 [/d] 不匹配的文本时遇到了麻烦。大多数使用否定的 vim 命令(例如:v)似乎只对整行而不是单个字符串进行操作,并且使用 %s 进行组匹配:
:%s/\v(.*)([\d])(.*)/\2

也匹配和删除方括号。

有人会建议解决我的问题吗?

最佳答案

你很接近。您需要引用方括号并使用比 .* 少得多的东西.

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

概述

匹配前导文本 + [ + 数字 + ] + 尾随文本。捕获 [ + 数字 + ] .替换匹配的捕获组。只留下括号和数字。

细节的荣耀
  • 使用 \v非常神奇。见 :h magic
  • [...]是一个括号中的字符类,它匹配里面的任何字符。例如fooba[rs]匹配 foobarfoobas ,但不是 foobaz .见 :h /\[ . (注意 Vim 可能将其称为集合。)
  • [^...]是一个否定的括号字符类,因此不匹配括号内的任何字符。例如fooba[^rz]匹配 foobas ,但不是 foobazfoobar .
  • [^[] - 匹配任何非 [特点。 (这看起来很有趣)
  • [^[]* - 匹配是非 [字符零次或多次。这将匹配我们要删除的前导文本。
  • (...) - 捕获组
  • \[ & \]表示文字 [/] .我们必须转义以防止字符类。
  • \d匹配 1 个数字。
  • [^[]* - 匹配要删除的尾随文本
  • \1替换将是我们的捕获组又名括号数字。
  • 使用 g标记以全局或更简单地多次执行此操作。
  • 使用范围 %做一个替换,:s , 在整个文件中, 1,$ .

  • 那么为什么:%s/\v(.*)([\d])(.*)/\2失败?

    tl;dr:您的模式不匹配。试试 /[\d] .

    长版:
  • 第一.*将捕获太多只留下最后一部分。例如[2]... .
  • [\d]创建与以下字符之一匹配的括号字符类:d\
  • 第二个.*使用 g 时遇到与第一个相同的问题旗帜。
  • 为什么不是 3 个捕获组?你当然可以有更多的捕获组,但在这种情况下它们是不必要的,所以删除它们。
  • 失踪 g旗帜。这意味着该命令每行只会进行 1 次替换,这将留下大量文本。

  • 一般正则表达式和替换建议

    在处理棘手的正则表达式模式时,通常最好从搜索开始,/ , 而不是替代品。这使您可以事先查看匹配项的位置。您可以通过 / 调整您的搜索并按下 <up><c-p> .甚至更好地使用 q/打开command-line-window所以你可以像编辑任何文本一样编辑你的模式。您也可以使用 <c-f>在命令行(包括 / )上调出 command-line-window .

    一旦你有了你的模式,那么你就想开始你的替换。 Vim 通过使用空模式提供了使用当前搜索的快捷方式。例如 :%s//\1/g .

    这种技术特别与 set incsearch 结合使用和 set hlsearch , 意味着您可以在进行替换之前以交互方式查看您的匹配项。此技术显示在以下 Vimcast 中插曲:Refining search patterns with the command-line window .

    需要学习更多正则表达式语法吗?见 :h pattern .这是一篇很长很密集的读物,但对你将来会有很大帮助。我还发现通过 perldoc perlre 阅读 Perl 的正则表达式文档也是一个好看的地方。注意:Perl 的正则表达式与 Vim 的正则表达式不同(参见 :h perl-patterns),但 Perl 兼容正则表达式 (PCRE) 非常常见。

    想法

    您也可以考虑grep -o .例如%!grep -o '\[\d\]' .

    更多帮助
    :h :s
    :h range
    :h magic
    :h /\[
    :h /\(
    :h s/\1
    :h /\d
    :h :s_flags
    :h 'hlsearch'
    :h 'incsearch'
    :h q/
    :h command-line-window
    :h :range!
    

    关于regex - 使用 vim 替换出现次数可变的不匹配字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31544848/

    相关文章:

    javascript - 如何使用 jQuery 删除元素内的文本?

    ruby - Parslet 中是否提供反向引用?

    ubuntu - vim 大小不是终端的全尺寸

    VIM获取E488尾随字符

    ruby - 有没有办法在 Vim 中为 Ruby 设置良好的自动完成?

    delphi - 在 Delphi 中替换可视化组件的最佳方法

    python - pandas - pd.replace 和 TypeError

    html - Firefox 输入模式正则表达式范围

    java - 如何在 JSP 中使用正则表达式打印 HTML 标签?

    javascript - JavaScript 中的正则表达式可选字符集