去年,我开始使用 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)复制/粘贴兼容