使用正则表达式在 Vim 中的每个捕获组中用下划线替换空格

Replacing spaces with underscores within each capture group in Vim using regex

我经常在使用 Power BI 时使用 Vim 编辑 Power Query“M”代码。通常我更喜欢为每个更改自动生成的标识符名称 通过用下划线替换空格并将其转换为小写来查询步骤。带空格的标识符表示为带# 前缀的引号字符串 比如#"Change Column Types"。对于该示例,我希望每个实例都转换为 change_column_types。 我想创建一个可以在所有实例的任何缓冲区内执行此操作的键映射。

示例文件如下所示,后面是所需的 'cleaned' 文件:

输入:

let
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"id", Int64.Type}, {"foo", type text}, {"bar", type text}, {"baz", Int64.Type}}),
    #"Filtered Rows" = Table.SelectRows(#"Changed Type", each ([foo] = "sdf")),
    #"Grouped Rows" = Table.Group(#"Filtered Rows", {"bar"}, {{"Count", each Table.RowCount(_), Int64.Type}})
in
    #"Grouped Rows"

期望的输出:

let
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
    changed_type = Table.TransformColumnTypes(Source,{{"id", Int64.Type}, {"foo", type text}, {"bar", type text}, {"baz", Int64.Type}}),
    filtered_rows = Table.SelectRows(changed_type, each ([foo] = "sdf")),
    grouped_rows = Table.Group(filtered_rows, {"bar"}, {{"Count", each Table.RowCount(_), Int64.Type}})
in
    grouped_rows

诀窍在于,这涉及尝试替换每个捕获组中的多个(未知数量的)字符。 由于每个单词通常只有 2 或 3 个单词,我可以使用两个 ex 命令以一种 hacky 的方式处理这些单词:

:%s/\v\#"(\w+)\s(\w+)"/\L_\L/gc
:%s/\v\#"(\w+)\s(\w+)\s(\w+)"/\L_\L_\L/gc

但是,这显然并不理想,因为它被硬编码为仅支持特定数量的单词。 我试过做一些嵌套分组,但问题似乎还是一样。 有没有办法在其他一些替换操作中定义替换模式? 任何有关如何正确处理此问题的帮助将不胜感激。

下面为 <space>-<c> 创建一个映射以将字符串转换为标识符:

noremap <space>c :%s/#"\([^"]\+\)"/\=substitute(tolower(submatch(1)), " ", "_", "g")/g<CR>

关于这里发生的事情的一点解释 - 替换的替换部分的 \= 部分表示我们将把这个表达式作为 vim 脚本来评估,而不是将其视为文字文本。我们使用 submatch(1) 获取第一个捕获组的文本,将其转换为小写,然后进行第二次替换(空格为下划线)。


请注意,有一些边缘情况可能会遇到问题 - 如果需要,我可以将正则表达式编辑得更复杂(并且可能更脆弱)以处理这些情况。

  • 如果字符串可以以单引号而不是双引号开头,则不会匹配它们。我不知道这是否是 Power Query“M”会遇到的问题。
  • 如果字符串包含转义字符(反斜杠),则不会处理。
  • 如果字符串以数字开头,这可能无法成为目标语言/格式(如果它与大多数语言一样)的有效标识符。