递减时,Vim会从某些数字前面删除零:
如果我带有以下文本文件:
a02
a03
a04
a05
a06
a07
a08
a09
a10
a11
Run Code Online (Sandbox Code Playgroud)
并使用ctrl+V
突出显示第二列和第三列,然后点击ctrl+X
减少,我留下:
a01
a02
a03
a04
a05
a06
a7
a8
a9
a10
Run Code Online (Sandbox Code Playgroud)
我正在运行Vim版本7.4.1689并且我没有通过我的.vimrc加载它
$ vim -u NONE
Run Code Online (Sandbox Code Playgroud)
发生这种情况是因为Vim会自动识别并转换八进制值.
来自help(:h variables
):
从Number到String的转换是通过使用Number的ASCII表示.
例子:
Run Code Online (Sandbox Code Playgroud)Number 123 --> String "123" Number 0 --> String "0" Number -1 --> String "-1"
通过将第一个数字转换为数字来完成从字符串到数字的转换.识别十六进制"0xf9",八进制"017"和二进制"0b10"数字.如果String不以数字开头,则结果为零.
例子:
Run Code Online (Sandbox Code Playgroud)String "456" --> Number 456 String "6bar" --> Number 6 String "foo" --> Number 0 String "0xf1" --> Number 241 String "0100" --> Number 64 String "0b101" --> Number 5 String "-8" --> Number -8 String "+8" --> Number 0
您的值02
通过07
被识别为有效的八进制值并保存为,01
通过递减到八进制06
.
当你到达08
它不是一个有效的八进制值.它被视为字符串08
,转换为十进制值8
,并递减为7
.这种情况再次发生09
,最终成为现实8
.
该10
和11
值以及递减十进制.因为10
是十进制而不是八进制,所以你得不到0
结果9
值的前导.
我不知道用减量命令做你想做的事情的方法.
编辑:找到这个答案后,我测试了这个表达式,它在你的特定情况下做了你想做的事情:
:%s/\v[0-9]+/\=printf("%02d", substitute(submatch(0), '^0\+', '', 0)-1)/
Run Code Online (Sandbox Code Playgroud)
我不确定这是否能解决您的一般用例,因为它与使用选择的原始操作完全不同.但对于您提供的文件,它可以实现您所追求的结果.
解剖一下来解释一下:
首先,我们首先调用global子命令%s
并传递\v
标志以打开"非常神奇"的模式.这可能会也可能不会根据您的设置更改行为,但这是一个公开示例,因此它包含在此处以确保模式处于活动状态.
:%s/\v
Run Code Online (Sandbox Code Playgroud)
然后,我们找到所有连续的数字序列.这将从您的示例中找到02
,03
等等.
[0-9]+
Run Code Online (Sandbox Code Playgroud)
然后在替换部分,我们有这个命令,它完成了真正的工作:
\=printf("%02d", substitute(submatch(0), '^0\+', '', 0)-1)
Run Code Online (Sandbox Code Playgroud)
该substitute()
函数确定新值是什么.submatch(0)
意味着使用整场比赛.使用模式^0\+
和替换(空字符串)表示从任何具有一个的数字中去除前导零.将0
在年底不是太重要; 它只是说该substitute()
功能没有标志.
该substitute
命令的结果是一个数字.说02
被剥夺了2
.使用- 1
最后,我们从该结果中减去1(减量).
最后,将此结果传递给printf
函数.使用格式字符串%02d
表示将值打印为十进制,以2位宽格式打印,使用前导零填充.