【问题标题】:VIM substitution with multiple patterns具有多种模式的 VIM 替换
【发布时间】:2016-11-17 23:27:00
【问题描述】:

我需要修改如下所示的字符串集:

debug("some random text:  val " + arg1);

debug("some random text:  val " + arg1 + " val2 " + arg2);

debug("some random text:  val " + getValue(1) + " val2" + getValue(2) + ".");

或任何类似的组合。例如,可能有 0 个或多个 'args' 都需要替换

进入

debug("some random text:  val ", arg1);

debug("some random text:  val {} val2 {}", arg1, arg2);

debug("some random text:  val {} val2 {}.", getValue(1), getValue(2));

基本上取每个匹配 + .* + 替换为 {} 的参数,并将匹配的参数放在“带引号的字符串”的末尾,用逗号和相同的顺序。 所以最终结果的一般形式应该是这样的:

("this is a quoted {} string with {} tokens {} in it", arg1, arg2, arg);

【问题讨论】:

  • 你的第一个例子看起来不对;它不包含{}
  • 可以接受使用:perldo 的解决方案吗?
  • 如果有人能一步一步地做到这一点,那就太棒了:D
  • Ruud 的回答非常适合我的目的,因为我手动执行此操作并验证结果。但是,如果有人知道另一种方法会很好,也许使用 sed 和/或 awk...

标签: regex vim awk replace sed


【解决方案1】:

最简单的方法是分多个步骤进行。以下方法所需的步骤数等于任何单个调试语句中的最大参数数加一。

示例文本文件:

debug("some random text:  val " + arg1);
debug("some random text:  val " + arg1 + " val2 " + arg2);
debug("some random text:  val " + getValue(1) + " val2" + getValue(2) + ".");

我们首先在必要时附加一个空字符串文字。

:g/^\s*debug("/s/[^"[:blank:]]\s*\zs\ze);/ + ""/

请注意第 1 行和第 2 行是如何受到影响的,但第 3 行不会受到影响。这是故意的;第 3 行已经以字符串文字结束。

debug("some random text:  val " + arg1 + "");
debug("some random text:  val " + arg1 + " val2 " + arg2 + "");
debug("some random text:  val " + getValue(1) + " val2" + getValue(2) + ".");

接下来,我们将每个第一个参数移动到位。

:g/^\s*debug("/s/"\s*+\([^+]\{-}\)\s*\(+\s*"\(.*\)\)\?\ze);/{}\3,\1/

注意第二个(和后面的)参数是如何不受影响的。

debug("some random text:  val {}", arg1);
debug("some random text:  val {} val2 " + arg2 + "", arg1);
debug("some random text:  val {} val2" + getValue(2) + ".", getValue(1));

重复相同的命令。最简单的方法是按@:

debug("some random text:  val {}", arg1);
debug("some random text:  val {} val2 {}", arg1, arg2);
debug("some random text:  val {} val2{}.", getValue(1), getValue(2));

对具有两个以上参数的行继续重复。一旦命令不再影响任何行,您就完成了。

注意事项:

  • 我是在假设每个调试语句(包括所有参数)占用一行的情况下进行此操作的。
  • 使用的正则表达式可能需要对更复杂的参数表达式进行一些调整(例如,本身包含 + 运算符的表达式)。
  • 建议您事后使用 diff 工具手动验证结果。

【讨论】:

  • 酷,我从来不知道@:,谢谢!当然,在第一次之后它变得更加容易,因为你可以使用@@
  • 像冠军一样工作!
【解决方案2】:

对于一个相对“封闭”的解决方案(对于多个参数,您仍然需要多次执行该命令),重复此命令直到没有更多更改:

(例如单行):

:s/\([^"]*"[^"]*\)"\s*+\s*\([^ ,]\+\)\(\s*+\s*"\)\=\(\([^"]*\)"\)\=\(.*\)\([^"]*\));/\1{}\5"\6, \2\7);/

说明:
该表达式将代码分解为以下九个元素,包括七个带括号的元素(\1、...、\7,由左括号的顺序标识)和两个非括号元素(列为--下面):

/\([^"]*"[^"]*\)"\s*+\s*\([^ ,]\+\)\(\s*+\s*"\)\=\(\([^"]*\)"\)\=\(.*\)\([^"]*\));/
   ----\1-----            --\2---    ---\3---        -\5--         \6    -\7--                                                          
                                                   ----\4----

\1: [^"]*"[^"]\*    " Up to second quote (i.e. up to first closing quote)
--: "\s*+\s*        " The first closing quote and '+' operator
\2: [^ ,]\+         " The first concatenated arg (to be converted into an argument list element)
\3: \s*+\s*"        " The following '+' operator and opening quote of the second string (if present) - discard
\4: \([^"]*\)"      " The second string (if present), so we can close the quotes on our (newly combined?) first string
\5:                 " (Embedded in \4 above) - the second string minus the closing quote (the part we want)
\6: .*              " Everything up to the final quote (if there are any more); no more quotes after this
\7: [^"]*           " Everything else (up to closing paren)
--: );              " The end

并且列为“如果存在”等的元素或子元素用\= 限定。我们使用\1\2(在其新位置)、\5\6\7 构建我们想要的结果。

在开头添加一个范围或限定模式,如@Ruud 的答案一次执行多行(我倾向于只使用范围%,如:%s/// 中的整个文件,但这可能也匹配一些意外的行)。

@Ruud 提到的所有相同的警告在这里也适用 - 假设每个语句都在一行中,可能不考虑参数中更复杂的表达式等。

与多步骤或脚本方法相比,这样的表达式需要大量的工作来提出和调试,但它确实是一个有趣的练习 =)。

【讨论】:

    猜你喜欢
    • 2022-06-15
    • 2019-05-23
    • 2015-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-27
    • 1970-01-01
    • 2014-10-06
    相关资源
    最近更新 更多