我希望使用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
还匹配并删除方括号。
有人有建议解决我的问题吗?
答案 0 :(得分:4)
你很亲密。你需要引用方括号并使用比.*
更少贪心的东西。
:%s/\v[^[]*(\[\d\])[^[]*/\1/g
匹配前导文字+ [
+数字+ ]
+尾随文字。捕获[
+数字+ ]
。替换匹配捕获组。只留下括号和数字。
\v
非常神奇。请参阅:h magic
[...]
是一个括号内的字符类,它匹配里面的任何字符。例如fooba[rs]
匹配foobar
和foobas
,但不匹配foobaz
。见:h /\[
。 (注意Vim可能会将此称为集合。)[^...]
是一个否定括号的字符类,因此不会在括号内匹配任何字符。例如fooba[^rz]
匹配foobas
,但不匹配foobaz
和foobar
。[^[]
- 匹配任何非[
字符。 (这看起来很有趣)[^[]*
- 匹配为非[
字符零次或多次。这将匹配我们要删除的主要文字。(...)
- 捕获组\[
& \]
代表文字[
/ ]
。我们必须逃避以防止角色类。\d
匹配1位数。[^[]*
- 匹配要删除的尾随文本\1
替换将是我们的捕获组,也就是括号内的数字。g
标志可以全局或更明显地多次执行此操作。%
范围对整个文件:s
进行替换1,$
。:%s/\v(.*)([\d])(.*)/\2
会失败? tl; dr:你的模式并不匹配。试试/[\d]
。
长版:
.*
将捕获太多而只留下最后一部分。例如[2]...
。[\d]
创建一个括号中的字符类,其中包含以下字符之一:d
或\
.*
在使用g
标志时遇到与第一个问题相同的问题。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!
答案 1 :(得分:1)
另一种方法:
:%s/\v[^[]*(%(\[\d\])?)/\1/g