确定 vim 正则表达式替换

确定 vim 正则表达式替换

去年,我开始使用 Vimwiki 记录项目的每周进度。随着时间的推移,我的每周维基链接列表的格式发生了一些变化。今年年底,我决定快速浏览我的索引页面并统一我所做的要点的格式,但我就是无法获得正确的正则表达式。

我想要更新的项目符号的原始示例如下所示,其中包含上面的最新条目,采用我想要的格式。

 * [[2018_Week_25|Week 25, 17th through the 23rd June]]
 * [[2018_Week_24|Week 24, 10th through 16th June]]
 * [[2018_Week_23|Week 23, 3rd through 9th June]]
 * [[2018 Week 22|Week 22, 27th May through 2nd June]]
 * [[2018 Week 21]], 20th through 26th May
 * [[2018_Week_20]]
 * [[2018_Week_19]]
 * [[2018_Week_18]], 29th April through 5th May
 * [[2018_Week_17]], 22nd through 28th April
 * [[2018_Week_16]], 15th through 21st April
 * [[2018_Week_15]], 8th through 14th April
 * [[2018_Week_14]], 1st through 7th April
 * [[2018_Week_13]], 25th through 31st March

我首先进行了一个简单的匹配:

/\[\[\d+[_\s]Week[_\s]\d+\]\],\s\d+\w+.*/g

它与第 5、8-13 行的相应部分匹配。然后我尝试加入一些模式变量和替换,但一切都崩溃了。使用下面的替换行,Vim 突然决定不再找到它之前找到的模式。

:1,13s/\(2018[_\s]Week[_\s]\d\d\),\s\(\d+\w+\)/\[\[\1|\1\2\]\]/g
E486: Pattern not found: \(2018[_\s]Week[_\s]\d\d\),\s\(\d+\w+\)

我实际上已经尝试了很多这种微妙的变体,但我开始相信我只是忽略了一些显而易见的东西。有没有人有什么建议?

答案1

:%s/\(\[\[\d\+[_ ]\+Week\([_ ]\+\)\(\d\+\)\)\]\],\(.*\)/\1|Week\2\3,\4]]/

您仍然可以通过在\s*适当的情况下填充来改进此表达式,以更好地捕获手动键入的文本中总是出现的不一致。

您提出的解决方案存在一些问题:

  • 正则表达式:\(2018[_\s]Week[_\s]\d\d\),\s\(\d+\w+\) 不匹配,因为:

    • 反斜杠转义的预定义字符类不能在由 分隔的用户定义字符类中使用[][_\s]匹配下划线、反斜杠或s字符。您可以_\|\s在这些情况下使用。
    • +字符需要对其特殊含义进行转义,因为“1 或更多”量词处于活动状态。否则,它与文字+符号匹配。
    • 该部分前面是要匹配的文本中的,\s\(\d+\w+\)序列匹配,但模式中缺少该序列匹配。\]\]\]\]
  • 不考虑替换字符串中反斜杠的问题,您尝试通过 终止生成的字符串]],但仅使用 匹配直到指定逗号后的日期的部分\d\+\w\+。这意味着如果替换成功,您的行将以如下文本结尾:29th]] April through 5th May,具有]]应该在中间某处终止该行的序列。

  • 替换字符串:\[\[\1|\1\2\]\] 不是正则表达式,因此,像[和 之类的字符]不需要转义。

  • 另外,\d\+\w\+虽然没有错误,但却是多余的,因为\w已经涵盖了所有内容\d以及您使用表达式的前面部分指定其上下文的方式,它总是匹配诸如 等之类的内容9th,并且从不匹配任何不好的内容。

编辑:@user1133275 的一个非常好的建议是(经过一些更改)在原始解决方案中的捕获组中使用逗号,也可以更改未指定日期间隔的行,即。没有“xth 到 yth”:

:%s/\(\[\[\d\+[_ ]\+Week\([_ ]\+\)\(\d\+\)\)\]\]\(,.*\)\?/\1|Week\2\3\4]]/

@user1133275没有提供答案,所以我把我们讨论的结果放在这个答案的评论部分。如果他们决定将其放入答案中并且我收到通知,我将删除此编辑,以便将学分归于基本想法的作者。

答案2

如果我正确理解你的问题,以下替换应该可以满足你的要求:

%s/\[\[\(\d\+\)\([_ ]\)Week\([_ ]\)\(\d\+\)\]\],\(\s\d\+\w\+.*\)/[[\1\2Week\3\4|Week \4,\5]]/

注意:\([_ ]\)捕获组保留出现在 之前的组件的分隔符(空格或下划线)|(分隔符是第 5 行的空格,而下划线用于第 8-13 行)。

答案3

vim 正则表达式是非标准的,因此只需在 vim 中使用业界领先的 perl 即可;

:%!perl -pe '$RE'

你可以在 vim 之外进行测试;

> echo "[[2018_Week_18]], 29th April through 5th May" \
| perl -pe 's/[_ ](Week)[_ ](\d+)\]\](, .*)?/_$1_$2|$1 $2$3]]/g'
[[2018_Week_18|Week 18, 29th April through 5th May]]

除了 perl RE 的长度约为 vim RE 的 1/2 之外,perl RE 还与许多其他工具(grep/rename/vim/sed/awk/etc)复制/粘贴兼容

相关内容