Vim复杂的正则表达式

时间:2017-11-10 12:27:28

标签: regex vim

我在文件中包含这些字符串:

a b
a-b
a / b / c

我想用以下内容替换它们:

"a b" => a_b
"a-b" => a_b
"a / b / c" => a_b_c

如何编写正则表达式?还请解释正则表达式并命名所涉及的概念。

5 个答案:

答案 0 :(得分:2)

这不仅仅是替换中的简单捕获和重新排序。将非字母字符修改为_需要包含匹配的替换。这可以通过:help sub-replace-expr

完成
:%substitute/.*/\='"' . submatch(0) . '" => ' . substitute(submatch(0), '\A\+', '_', 'g')/

基本上,这匹配整行,然后替换为双引号中的匹配,后跟=>,然后匹配非字母字符序列(\A\+)替换为单_ 1}}。

替代

您也可以分两步执行此操作:首先复制并引用该行:

:%substitute/.*/"&" => &/

然后,需要修改第二个副本。要将替换应用于仅在=>分隔符后匹配,必须提供肯定的后视(必须在=> +任何字符之后匹配):

:%substitute/\%(=> .*\)\@<=\A\+/_/g

答案 1 :(得分:2)

另一种方式:

:g/^/co.|-s/.*/"&" =>/|+s/\W\+/_/g|-j

概述:

对于每一行:g/^/,复制一行(:copy),然后替换为在第一行添加"..." =>并对其上的非字母字符进行替换下一行_。然后加入两行-j

细节的荣耀:

  • :g/{pat}/{cmd} - 在与{cmd}匹配的每一行上运行{pat}。使用^匹配每一行
  • copy . - 复制当前行(.)下方的当前行。简短:co.
  • -1s/.*/.../ - :s上面一行(-1)。替换整行,.*
  • "&" => - &是整个匹配(或PRCE中的\0
  • +s/\W\+/_/g - 在:s
  • 的所有非字母数字字符的下一行(+1)上执行全局_
  • -j - 从上面一行开始:join使用下一行

获取更多帮助:

:h :g
:h :copy
:h :s
:h :j
:h :range

答案 2 :(得分:1)

这样做的一种方法:

:%s/[\ -]\/*\ */_/g

[\ -]会查找空格\(请注意\-之间的空格)或短划线-

星号*表示0或N次出现。所以\/* 0或N次出现斜线/; \ * 0或N次出现的空格。最后g替换该行中的所有匹配项。

<强> [编辑]

我误解了这个问题。您的问题可以通过两个步骤使用多个子表达式来解决。

步骤1)在c

之前加上下划线
:%s/c/_c/g

步骤2)找到并替换

:%s/a\([\ -]\/*\ *\)b\(\1\)*\(_\)*\(c\)*/"a\1b\2\4" => a_b\3\4/g

这会给你

"a b" => a_b
"a-b" => a_b
"a / b / c" => a_b_c

说明:

\(\)表示一个子表达式,外观顺序很重要,因此\ 1与子表达式1匹配等等。

诀窍是在某个地方添加_,以便我们可以使用它,同时获取有关长度的信息。因为它只出现在c之前,所以子表达式\3只匹配该行的_

现在,通过"a\1b\2\4"替换,我们跳过\3,避免添加下划线。

答案 3 :(得分:1)

这实现了你所要求的,虽然这个问题有些含糊不清:

%s/\(\a\)\A\+/\1_/g

%s / [find_pattern] / [replace_pattern / g确实查找并替换文件中的每一行(%),并执行任意数量的匹配(g),而不是第一个匹配的默认行为。

(\ a)捕获(括号必须转义),包含字母字符。

\ A +表示一个或多个非字母字符

/ 1是模式中第一个捕获的反向引用。在这种情况下,括号中的字母字符。

_只是文字。

所以它一起取代每个字母,后跟一个或多个非字母,后跟_。所以这仅在行以最后一个字母结束时才有效。

答案 4 :(得分:1)

:%s:[\ /-]\+:_:g

说明:

  s:        : :  - Substitute command (with delimiter `:`)
    [\ /-]       - Match a ` ` (space), `/`, or `-` character
          \+     - Match one or more of the previous group consecutively
             _   - Replace with one `_` character
               g - Replace all matches in line
 %               - Execute command on every line in file (optional)

我将您的问题解释为非常通用。如果您需要匹配更具体的模式,请准确说明需要匹配的内容。

[编辑]

如果您需要完全匹配' / ',请使用:

:%s:\ /\ \|[\ -]:_:g

  s:            : :  - Substitute command (with delimiter `:`)
         \|          - Match left pattern OR right pattern
    \ /\             - Match ` / ` exactly
           [\ -]     - Match a ` ` (space) or `-` character
                 _   - Replace with one `_` character
                   g - Replace all matches in line
 %                   - Execute command on every line in file (optional)

[编辑2]

我误解了你想要替代的东西。

如果你正试图用a做这件事,那么你的生活将会非常困难 单一的正则表达式。它会变得如此复杂,此时你会变得更好 写一个小函数,就像其他一些答案一样。但你应该这样 能够逃脱两个替换命令,而不会太疯狂。 一个用于前两个字符串(a ba-b),另一个用于第三个字符串 (a / b / c)。

%s:\v(\a+)[\ -](\a+):"\0"\ =>\ \1_\2
%s:\v(\a+)\s*/\s*(\a+)\s*/\s*(\a+):"\0"\ =>\ \1_\2_\3

说明:

%s:\v(\a+)[\ -](\a+):"\0"\ =>\ \1_\2

 s:                 :                - Substitute command (with delimiter `:`)
   \v                                - Very Magic mode *
     (   )     (   )                 - Capture contained matches into numbered sub-expressions
      \a+       \a+                  - Match at least one alphanumeric character
          [\ -]                      - Match either ` ` (space) or `-`
                     "  "\ =>\   _   - Literal text
                      \0             - Replace with entire matched text
                               \1 \2 - Replace with first and second `()` sub-expression, respectively
 %                                   - Execute command on every line in file (optional)

%s:\v(\a+)\s*/\s*(\a+)\s*/\s*(\a+):"\0"\ =>\ \1_\2_\3

 s:                               :                   - Substitute command (with delimiter `:`)
   \v                                                 - Very Magic mode *
     (   )       (   )       (   )                    - Capture contained matches into numbered sub-expressions
      \a+         \a+         \a+                     - Match at least one alphanumeric character
          \s*/\s*     \s*/\s*                         - Match a `/` and any surrounding spaces
                                   "  "\ =>\   _  _   - Literal text
                                    \0                - Replace with entire matched text
                                             \1 \2 \3 - Replace with first, second, and third `()` sub-expression, respectively
 %                                                    - Execute command on every line in file (optional)

* This eliminates the need for a lot of ugly backslashes.
  See `:h /magic` and `:h /\v`