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

Regex 使用vim替换出现次数可变的不匹配字符串,regex,vim,replace,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]

我希望使用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]。大多数使用否定(例如:v)的vim命令似乎只在整行而不是单个字符串上运行,并且使用%s进行组匹配:

:%s/\v(.*)([\d])(.*)/\2
还匹配并删除方括号


有人能给我一个解决问题的建议吗

你很接近。您需要引用方括号,并使用比
*
更不贪婪的内容

:%s/\v[^[]*(\[\d\])[^[]*/\1/g
概述 匹配前导文本+
[
+数字+
]
+尾随文本。捕获
[
+数字+
]
。替换与捕获组匹配的。只留下括号和数字

细节的荣耀
  • 使用
    \v
    非常神奇。请参见
    :h magic
  • […]
    是一个括号内的字符类,它匹配其中的任何字符。e、 g.
    fooba[rs]
    匹配
    foobar
    foobas
    ,但不匹配
    foobaz
    。请参阅
    :h/\[
    (注意,Vim可能将其称为集合。)
  • [^…]
    是一个用括号括起来的否定字符类,因此不匹配括号内的任何字符。例如,
    fooba[^rz]
    匹配
    foobas
    ,但不匹配
    foobaz
    foobar
  • [^[]
    -匹配任何非
    [
    字符。(这看起来很有趣)
  • [^[]*
    -匹配为非
    [
    字符零次或多次。这将匹配我们要删除的前导文本
  • (…)
    -捕获组
  • \[
    &
    \]
    表示文字
    [
    /
    ]
    。我们必须转义以防止字符类
  • \d
    匹配1位数字
  • [^[]*
    -匹配要删除的尾随文本
  • \1
    替换的将是我们的捕获组,即括号中的数字
  • 使用
    g
    标志全局或更明确地多次执行此操作
  • 使用范围
    %
    对整个文件
    1,$
    执行替换
    :s
那么为什么
:%s/\v(.*)([\d])(.*)/\2
会失败呢? tl;dr:您的模式不匹配。请尝试
/[\d]

长版本:

  • 第一个
    *
    捕获的内容太多,只剩下最后一部分。例如,
    [2]…
  • [\d]
    创建一个括号内的字符类,该类与下列字符之一匹配:
    d
    \
  • 第二个
    *
    在使用
    g
    标志时遇到与第一个相同的问题
  • 为什么不是3个捕获组呢?您当然可以有更多的捕获组,但在这种情况下它们是不必要的,所以请删除它们
  • 缺少
    g
    标志。这意味着命令每行只进行一次替换,这将留下大量文本
一般正则表达式和替换建议 在使用复杂的正则表达式模式时,通常最好从搜索开始,而不是替换。这允许您查看匹配项的位置。您可以通过
/
并按
调整搜索。或者更好地使用
q/
打开
命令行窗口
(包括
/
)打开
命令行窗口

一旦有了模式,您就要开始替换。Vim提供了一个使用空模式使用当前搜索的快捷方式。例如
:%s//\1/g

此技术尤其与
set incsearch
set hlsearch
相结合,意味着您可以在进行替换之前以交互方式查看匹配项。此技术将在下一集中显示:

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

思想

你也可以考虑<代码> GRP-O < /代码>。例如<代码> %.GRP-O \ \ \\\\代码> < /P> 更多帮助 另一种方法是:

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

这真的很有帮助。对于
[^[]
我一直认为第二个括号是配对的,这让我完全困惑。
:%s/\v[^[]*(%(\[\d\])?)/\1/g