Vim - 在不改变列宽的情况下增加数字
Vim - Increase number without changing column width
我正在处理固定宽度的文件格式,我需要增加某些列中的所有数字。我有一个简单的宏,它向数字添加一个值,移动到下一行并重复(如 2aj)但是,这些数字从 1 开始,通常结束于 10000 以上,因此列宽变得混乱,例如(下划线为spaces,本例仅涵盖从9到10的跳转)
FOO_7_BAR
FOO_8_BAR
FOO_9_BAR
变成
FOO_9BAR
FOO_10_BAR
FOO_11_BAR
(注意新的文本栏会破坏我的程序)
当我需要的时候
FOO_9_BAR
FOO10_BAR
FOO11_BAR
我一直在手动检查并从前 9 列中删除 space,然后是 90 列,然后是 900 列,但我正在寻找一种更可靠的方法来处理这个问题而不处理前 10 列, 100、1000 等,使用不同的宏或任何手动输入。
谢谢。
我是这样想的,我觉得动画本身就说明了:
最后的结果是:
FOO 3 BAR
FOO 4 BAR
FOO 5 BAR
FOO 6 BAR
FOO 7 BAR
FOO 8 BAR
FOO 9 BAR
FOO10 BAR
FOO11 BAR
这需要一些手动操作,但仍然比手动删除空格要好。
不过,您也可以通过 Vimscript 编写一个自动执行此操作的函数!
首先,找出最短线的长度。你可以通过 ex 做到这一点。 :echo col("$")
在最短的线上。
然后,运行以下命令:
:g/.\{NUM\}/exec "norm! /[0-9]\<cr>X"
将上面命令中的 NUM 替换为您在上一步中得到的原始数字。
以下是其工作原理的解释:
:g/.\{NUM\}/ Find lines that are too long
exec "norm! A common idiom: build a string to execute in normal mode
/[0-9]<cr> Find the first number on the line
X Delete the space before it (equivalent to "hx")
然后简单地重复运行同样的命令(你可以按:Up Return) 直到所有行的长度都相同——一旦出现这种情况就会导致错误(因为它不会找到任何匹配的行)。
这是整个过程的简短动画:
这可以用 :s
和一个子替换表达式来完成。
:%s/\v([^0-9]*)(\d+)/\=strpart(submatch(1), 0, 5 - len(submatch(2))).submatch(2)
我们的想法是捕获数字之前的部分和数字本身。替换通过 \=
执行 vim 表达式,将两个捕获组重新组合在一起。但是,通过 strpart()
将第一个捕获组切片为固定宽度(本例中为 5)减去第二个捕获组的长度 len(submatch(2))
.
如需更多帮助,请参阅:
:h sub-replace-expression
:h strpart()
:h len()
我正在处理固定宽度的文件格式,我需要增加某些列中的所有数字。我有一个简单的宏,它向数字添加一个值,移动到下一行并重复(如 2aj)但是,这些数字从 1 开始,通常结束于 10000 以上,因此列宽变得混乱,例如(下划线为spaces,本例仅涵盖从9到10的跳转)
FOO_7_BAR
FOO_8_BAR
FOO_9_BAR
变成
FOO_9BAR
FOO_10_BAR
FOO_11_BAR
(注意新的文本栏会破坏我的程序)
当我需要的时候
FOO_9_BAR
FOO10_BAR
FOO11_BAR
我一直在手动检查并从前 9 列中删除 space,然后是 90 列,然后是 900 列,但我正在寻找一种更可靠的方法来处理这个问题而不处理前 10 列, 100、1000 等,使用不同的宏或任何手动输入。
谢谢。
我是这样想的,我觉得动画本身就说明了:
最后的结果是:
FOO 3 BAR
FOO 4 BAR
FOO 5 BAR
FOO 6 BAR
FOO 7 BAR
FOO 8 BAR
FOO 9 BAR
FOO10 BAR
FOO11 BAR
这需要一些手动操作,但仍然比手动删除空格要好。
不过,您也可以通过 Vimscript 编写一个自动执行此操作的函数!
首先,找出最短线的长度。你可以通过 ex 做到这一点。 :echo col("$")
在最短的线上。
然后,运行以下命令:
:g/.\{NUM\}/exec "norm! /[0-9]\<cr>X"
将上面命令中的 NUM 替换为您在上一步中得到的原始数字。
以下是其工作原理的解释:
:g/.\{NUM\}/ Find lines that are too long
exec "norm! A common idiom: build a string to execute in normal mode
/[0-9]<cr> Find the first number on the line
X Delete the space before it (equivalent to "hx")
然后简单地重复运行同样的命令(你可以按:Up Return) 直到所有行的长度都相同——一旦出现这种情况就会导致错误(因为它不会找到任何匹配的行)。
这是整个过程的简短动画:
这可以用 :s
和一个子替换表达式来完成。
:%s/\v([^0-9]*)(\d+)/\=strpart(submatch(1), 0, 5 - len(submatch(2))).submatch(2)
我们的想法是捕获数字之前的部分和数字本身。替换通过 \=
执行 vim 表达式,将两个捕获组重新组合在一起。但是,通过 strpart()
将第一个捕获组切片为固定宽度(本例中为 5)减去第二个捕获组的长度 len(submatch(2))
.
如需更多帮助,请参阅:
:h sub-replace-expression
:h strpart()
:h len()