递减时,Vim错误地删除了零

jml*_*son 1 vim

递减时,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)

Dan*_*owe 6

发生这种情况是因为Vim会自动识别并转换八进制值.

来自help(:h variables):

从Number到String的转换是通过使用Number的ASCII表示.

例子:

   Number 123      -->     String "123"
   Number 0        -->     String "0"
   Number -1       -->     String "-1"
Run Code Online (Sandbox Code Playgroud)

通过将第一个数字转换为数字来完成从字符串到数字的转换.识别十六进制"0xf9",八进制"017"和二进制"0b10"数字.如果String不以数字开头,则结果为零.

例子:

   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
Run Code Online (Sandbox Code Playgroud)

您的值02通过07被识别为有效的八进制值并保存为,01通过递减到八进制06.

当你到达08它不是一个有效的八进制值.它被视为字符串08,转换为十进制值8,并递减为7.这种情况再次发生09,最终成为现实8.

1011值以及递减十进制.因为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位宽格式打印,使用前导零填充.