VIM中常用序列生成及数值转换

本文提供了几个简单的脚本示例,演示如何进行ASCII字符到数字、数字到ASCII字符、十六进制到十进制及十进制到十六进制的转换。通过这些示例,读者可以更好地理解不同数值系统之间的转换方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

"output A-Z
exe "let i=65|while i<=90|put =printf('%c', i)|let i=i+1|endwhile"

"output '0-9A-F'
exe "let i=0|while i<16|put =printf('%X', i)|let i=i+1|endwhile"

"ascii to number
echo char2nr('a')

"number to ascii
echo nr2char( 97 )

"hex to dec
echo printf('%d', 0xff )

"dec to hex
echo printf('%X', 255)



<think>我们有一个需求:在Vim中将连续的空格替换为制表符(Tab)。这通常用于将代码中的空格缩进转换为制表符缩进。 思路: 1. 我们可以使用Vim的替换命令(:s)来实现。 2. 需要匹配连续的空格,但是注意:我们可能只想替换行首的连续空格(即缩进部分),或者替换所有连续的空格?根据需求,通常是针对缩进,所以我们可以限定在行首。 3. 然而,用户的问题没有特别说明,所以我们给出两种方案:一种是替换行首的连续空格,另一种是替换所有连续空格(但要注意,这样可能会影响非缩进部分的空格,比如字符串中的多个空格,这通常不是我们想要的)。 因此,我们分两种情况讨论: 情况一:只替换行首的连续空格(推荐) 命令:`:%s/^\(\t*\) \{2,}/\=substitute(submatch(0), ' ', '\t', 'g')/` 但是这个方法比较复杂,我们可以用另一种方式:使用`\t`来代表制表符,并且匹配行首的连续空格(至少两个,因为一个空格可能不是缩进,但通常缩进是多个空格)。 然而,有一个更简单的方法:使用`>`和`<`命令来调整缩进,但这里要求替换为制表符,所以直接替换更直接。 我们可以这样: :%s/^ \{2,}/\=repeat("\t", len(submatch(0))/2) " 但这样不准确,因为空格数可能不是2的倍数 或者,我们可以使用一个更精确的方法:将每2个、4个或8个空格(根据你的缩进设置)替换为一个制表符。但通常我们设置tabstop,比如一个制表符等于4个空格,那么我们可以: :%s/^ \{4}/\t/g 但是这样只能替换4个空格,不能替换任意连续多个空格。而且,如果连续空格不是4的倍数,那么我们需要分次替换?这样不理想。 更好的方法:使用表达式寄存器,将连续空格转换为相应数量的制表符,但注意,制表符是占一个字符,但代表多个空格(取决于tabstop设置)。实际上,我们想要的是:将连续n个空格(n是tabstop的倍数)转换为n/tabstop个制表符。但是,如果连续空格数不是tabstop的倍数,我们可能只想替换前面能整除的部分,剩下的保留?或者全部替换为制表符?但这样会导致不对齐。 所以,通常的做法是:假设我们使用4个空格作为一个制表符,那么我们可以将每4个连续空格替换为一个制表符。但是,如果某处有5个空格,那么前4个被替换为制表符,最后一个空格保留。 命令:`:%s/^\( *\)\@<= /\t/g` 但是这个命令会从行首开始,将每4个连续空格替换为制表符。注意,它只替换行首的(因为`^`表示行首,但`\( *\)\@<=`是一个正向回顾,确保我们是在行首的任意空格之后匹配4个空格,这样实际上会匹配行首的任意位置连续的4个空格)。但是这样会多次替换,直到没有连续的4个空格。 但是,这个命令有一个问题:它可能会替换非行首的空格,因为我们没有用`^`锚定整个匹配。实际上,我们可以用: :%s/^\s*\zs \{4}/\t/g 解释: ^\s* 匹配行首的任意空格(包括0个) \zs 设置匹配开始的位置,这样前面的部分不会被替换 \{4} 匹配4个空格 然后替换为\t 这个命令只会替换行首连续空格中的每4个空格为一个制表符。但是,它一次只替换4个空格,所以需要执行多次,直到没有连续的4个空格。我们可以用`%s///g`,但是`g`标志会在一行中替换所有匹配,所以一行中如果有多个连续的4个空格,都会被替换。 但是,如果一行行首有8个空格,那么执行一次这个命令,就会替换两次(因为有两个4个空格),所以实际上我们只需要执行一次。 但是,这个命令不会将5个空格的前4个替换,因为它是匹配连续的4个空格。所以,行首的8个空格会变成两个制表符,而5个空格会变成一个制表符加一个空格。 然而,用户可能希望将连续的空格(无论多少个)都转换为制表符,但是按照制表符的宽度来转换。所以,上面的方法符合要求。 但是,用户可能希望一次性将任意长度的连续空格(至少两个)替换为制表符,并且按照当前的tabstop设置(比如4)来转换。上面的命令已经可以,但是需要根据tabstop设置修改命令中的空格数。例如,如果tabstop是2,那么我们需要将命令中的4改为2。 情况二:替换所有连续的空格(不推荐,因为可能会破坏非缩进部分的空格) 命令:`:%s/ /\t/g` (将4个空格替换为一个制表符,同样需要根据tabstop设置) 或者,对于任意位置,但这样可能会替换掉非缩进部分的多个空格,比如字符串中的空格。 因此,我们通常只替换行首的连续空格。 但是,用户的问题没有明确,所以我们给出一个通用的方法,并提醒用户注意。 另外,Vim有一个retab命令,可以重新设置制表符,但它会根据当前的tabstop设置将空格转换为制表符,但只转换行首的空格(即缩进部分)?实际上,retab命令会转换所有的空格(根据tabstop),但这样可能会改变非缩进部分的空格(比如字符串中的多个空格),所以使用retab需要谨慎。 我们可以这样使用retab: 首先设置tabstop(例如4):`:set ts=4` 然后使用`:retab!` (加!表示同时修改非空白字符后的空格,即所有空格) 但如果不加!,则只修改前导空格(缩进部分)?实际上,retab命令不加!也会转换非缩进部分的空格,所以不安全。 因此,我们推荐使用替换命令,并且只针对行首。 总结: 方法1(针对行首,按固定tabstop替换): 假设tabstop为4,那么使用: :%s/^\( \{4}\)\+/\=repeat('\t', len(submatch(0))/4)/g 解释:匹配行首的一个或多个4个连续空格,然后用表达式计算:匹配到的字符串长度除以4,就是制表符的个数,然后用repeat函数重复制表符那么多次。 但是,这个表达式会匹配4,8,12,...个空格。如果空格数不是4的倍数,比如6个,那么只会匹配4个(因为`\+`是贪婪匹配,但6个空格只能匹配4个,然后剩下的2个不会被匹配,所以不会替换)。所以,我们想要匹配尽可能多的4的倍数?实际上,上面的命令会匹配4的倍数个空格(连续的4个空格的序列)。 但是,如果一行行首有6个空格,那么上面的命令会匹配4个空格(因为6个空格中,前4个是连续的4个空格,然后后面2个不是,所以只匹配前4个),然后替换为一个制表符,剩下2个空格。这符合我们的要求。 但是,我们可以用更简单的方法:将每4个连续空格替换为一个制表符,然后重复执行直到没有连续的4个空格。我们可以用: :%s/^\( \{4}\)\+/\=repeat('\t', len(submatch(0))/4)/g 或者,更直接: :%s/^ \{4,4}/\t/g 然后多次执行,直到没有连续的4个空格。但是这样需要执行多次,不方便。 方法2:使用retab命令,但需要先设置好tabstop,并且只希望它转换缩进部分。但是retab命令默认会转换所有位置的空格。所以我们可以先标记缩进部分,然后只对缩进部分进行retab?这比较复杂。 因此,我们推荐方法1,但需要根据用户的tabstop设置调整命令中的数字。 然而,用户可能不知道自己的tabstop设置,或者希望自动获取当前的tabstop值。我们可以用表达式: :%s/^\( \{'.&ts.'\}\)\+/\=repeat('\t', len(submatch(0))/&ts)/g 但是,在替换表达式中这样拼接字符串比较麻烦,而且不能直接使用&ts(因为表达式里不能直接访问选项,需要用`&ts`,但这样在字符串中不行)。我们可以这样: :let ts = &tabstop :%s/^\( \{'.ts.'\}\)\+/\=repeat('\t', len(submatch(0))/ts)/g 但是,在替换表达式中,我们无法使用外部变量(在Vim脚本中,替换表达式可以使用外部变量,但这里需要执行命令)。所以我们可以: :execute '%s/^\( \{' . &ts . '}\)\+/\=repeat("\t", len(submatch(0))/' . &ts . ')/g' 注意:这里需要转义,并且使用双引号。 但是,这个命令比较复杂,而且如果一行行首的空格数不是ts的倍数,那么它只能替换前面完整的ts的倍数部分。 方法3:使用retab命令,但只对缩进部分操作。我们可以先使用`:set noet`(关闭expandtab),然后执行`gg=G`(重新缩进,但这样会使用制表符?),但这样并不直接。 考虑到简单性,我们推荐一个简单的方法:使用`>>`和`<<`命令来调整缩进,但这需要手动操作每一行。 因此,我们给出一个折中的方案:使用替换命令,并假设tabstop为4(常见情况)。如果用户使用其他tabstop,自行修改。 命令1(针对tabstop=4): :%s/^ \{4,}/\=repeat('\t', len(submatch(0))/4)/g 但是,这个命令会匹配行首的至少4个空格,然后替换为相应数量的制表符(每4个空格一个制表符)。注意,如果空格数是5,那么5/4=1(整数除法),所以会替换成一个制表符?但这样会丢失一个空格?实际上,表达式是:repeat('\t', len(submatch(0))/4),那么5/4=1(整数除法,因为len(submatch(0))是5,5/4=1.25,在vim中整数除法会取整?不,vim中除法是浮点,但repeat要求整数,所以会取整?实际上,vim会自动取整。所以5个空格会替换成一个制表符,这样会少一个空格。所以不行。 我们需要保留剩余的空格?不,因为匹配的是至少4个空格,所以5个空格会被整个匹配,然后替换成一个制表符(因为5/4取整为1),这样会丢失一个空格。所以这个方法不行。 改进:我们只匹配4的倍数个空格?使用`\( \{4}\)\+`,这样匹配4,8,12,...个空格。那么5个空格就不会被匹配。所以不会替换。这样我们还需要再处理剩下的空格?不,这样不完整。 因此,我们换一个思路:将连续的空格分组,每4个一组,然后替换为一个制表符,直到剩下的不足4个。我们可以用循环替换,直到没有连续的4个空格。但是,在Vim中,我们可以用: :%s/^\(\(\t\| \{4}\)*\) \{4}/\1\t/g 解释: 行首,然后匹配一个组:这个组由制表符或者4个空格组成,重复0次或多次(记为A),然后后面跟着4个空格。 然后,我们将这4个空格替换为A加上一个制表符。这样,每次替换4个空格为一个制表符,并且保留之前的缩进(可能是制表符和空格)。 这样,一行中行首的连续空格会被逐步替换,直到不足4个。 但是,这个命令需要执行多次,直到没有匹配。我们可以用循环,或者用`%s///g`,但是一次命令只能替换一次(因为每次只替换一组4个空格)。所以我们可以用: :while search('^\(\t\| \{4}\)* \{4}', 'n') | %s//\=substitute(submatch(0), ' \{4}$', '\t', '')/ | endwhile 这个比较复杂。 因此,我们推荐一个简单但需要多次执行的方法:先执行一次替换4个空格为一个制表符,然后重复执行这个替换命令,直到没有替换发生。用户可以用`@:`重复上一次命令,或者用`&`重复上一次替换。 但是,如果用户想要一个命令完成,我们可以写一个函数。 考虑到用户可能只需要一个简单的命令,我们给出一个针对固定tabstop的替换命令,并说明其局限性。 最终,我们选择使用表达式替换,但计算制表符个数时用整除,并且将匹配到的空格全部替换为制表符和剩余的空格?这样不行,因为替换部分只能是一个字符串。 我们可以这样:将匹配到的空格分成两部分:完整制表符部分和剩余部分。但是替换表达式只能返回一个字符串。 所以,我们使用: :%s/^ \+\ze\S/\=repeat('\t', len(submatch(0))/4) . repeat(' ', len(submatch(0))%4)/g 解释: ^ \+ 匹配行首的一个或多个空格 \ze\S 设置匹配结束在非空白字符开始之前(确保我们只匹配行首的空格,直到第一个非空白字符) 然后,用表达式:生成制表符(个数为空格数除以4的整数部分)加上剩余的空格(个数为空格数模4)。 这样,如果行首有5个空格,那么会被替换为:一个制表符(4个空格)加上一个空格(5%4=1),所以总共还是5个字符的宽度(但实际显示宽度取决于制表符的设定,制表符宽度为4,所以一个制表符加一个空格显示为5个空格宽度)。 但是,这样替换后,缩进还是保持了原来的宽度,但是混合了制表符和空格。通常,我们可能希望全部是制表符,但这样会导致不足4的倍数的空格无法完全替换。所以,这取决于用户的需求。 如果用户希望全部替换为制表符,并且不保留剩余空格(即即使不足4个也用一个制表符代替,但这样会超出),那不行,因为一个制表符就是4个空格宽度。 因此,我们通常保留剩余的空格。 所以,这个命令可以: :%s/^ \+/\=repeat('\t', len(submatch(0))/4) . repeat(' ', len(submatch(0))%4)/g 但是,这个命令会替换所有行首的空格(不管后面是不是非空白字符)。注意,我们使用了`\ze\S`来确保只匹配到非空白字符之前,但是`\ze\S`并不消费非空白字符,所以它不会影响后面的内容。但是,如果一行全是空格,那么`\S`匹配不到,所以不会匹配?所以我们需要调整。 我们可以不用`\ze\S`,因为`^ \+`已经匹配行首空格,而且我们确实希望替换这些空格。但是,如果一行全是空格,那么也会被替换。这也没问题。 所以,命令为: :%s/^ \+/\=repeat('\t', len(submatch(0))/4) . repeat(' ', len(submatch(0))%4)/g 然后,将4替换为当前的tabstop值。如果用户想用当前的tabstop,那么需要动态获取。我们可以: :let ts = &tabstop :%s/^ \+/\=repeat('\t', len(submatch(0))/ts) . repeat(' ', len(submatch(0))%ts)/g 但是,这个命令需要分两步,我们可以写成一个命令: :execute '%s/^ \+/\=repeat("\t", len(submatch(0))/' . &ts . ') . repeat(" ", len(submatch(0))%' . &ts . ')/g' 注意:这里在字符串中使用双引号,并且拼接变量&ts。 但是,这个命令会将行首的连续空格替换为制表符和空格的混合,以保持缩进宽度不变。如果用户希望完全转换为制表符(即去掉多余的空格,用制表符代替,即使不足一个制表符宽度),那么就不需要剩余空格部分。但是这样可能会改变缩进宽度(比如5个空格会变成一个制表符,即4个空格宽度,所以缩进减少了)。所以通常我们保留剩余空格。 因此,我们给出这个命令作为解决方案。 另外,我们也可以使用retab命令,但retab命令会改变所有位置的空格(包括非缩进部分),所以不安全。如果用户确定文本中没有非缩进部分的连续空格(且长度等于tabstop的倍数),那么可以用: :set ts=4 " 设置你的tabstop :set noet " 确保noexpandtab,这样retab才会用制表符替换 :retab 但是,retab命令会将所有连续的ts个空格(不管在行首还是行中)替换为一个制表符,所以可能会破坏字符串中的空格。因此,我们不推荐。 所以,总结: 推荐使用替换命令,只替换行首的空格,并保留余数空格: :%s/^ \+/\=repeat('\t', len(submatch(0))/&ts) . repeat(' ', len(submatch(0))%&ts)/g 但是,在命令行中直接使用&ts,在替换表达式中,&ts不会被解释为选项值。所以我们需要用execute: :execute '%s/^ \+/\=repeat("\t", len(submatch(0))/' . &ts . ') . repeat(" ", len(submatch(0))%' . &ts . ')/g' 注意:这里需要将制表符用双引号,因为整个表达式在双引号字符串中。 测试:假设当前tabstop=4,一行行首有5个空格,那么替换后,应该是一个制表符(占4个空格宽度)加一个空格。 但是,用户可能希望将行首的空格全部替换为制表符(不考虑余数),那么我们可以用: :%s/^ \+/\=repeat('\t', (len(submatch(0))+&ts-1)/&ts)/g 这样,5个空格会被替换为2个制表符(因为(5+4-1)/4=8/4=2),这样缩进就变成了8个空格宽度。这可能是用户不希望的。 因此,我们保留余数空格的方法更安全。 最后,我们给出一个简单的示例(tabstop=4): :%s/^ \+/\=repeat('\t', len(submatch(0))/4) . repeat(' ', len(submatch(0))%4)/g 用户可以根据自己的tabstop修改命令中的4。 如果用户想查看当前的tabstop,可以用`:set ts?`。 注意:这个命令只会替换行首的连续空格,不会影响行中的空格。 所以,最终答案: 在Vim中,你可以使用以下命令将行首的连续空格替换为制表符(同时保留不足一个制表符宽度的空格): :%s/^ \+/\=repeat('\t', len(submatch(0))/4) . repeat(' ', len(submatch(0))%4)/g 请将命令中的数字4替换为你设置的tabstop值。如果你不知道tabstop的值,可以通过`:set ts?`查看,然后使用以下命令(假设tabstop为8): :%s/^ \+/\=repeat('\t', len(submatch(0))/8) . repeat(' ', len(submatch(0))%8)/g 如果你希望用一个命令自动获取tabstop并替换,可以使用: :execute '%s/^ \+/\=repeat("\t", len(submatch(0))/' . &ts . ') . repeat(" ", len(submatch(0))%' . &ts . ')/g' 注意:这个命令只替换行首的空格,不会影响行中其他部分的空格。 如果文本中可能包含制表符,我们的命令仍然有效,因为在匹配时`^ \+`只匹配空格(不包括制表符),所以不会匹配到制表符。如果你想同时处理制表符和空格混合的情况,那将更复杂,这里不展开。 因此,我们推荐上述命令。 相关问题: 1. 如何在Vim中将制表符转换为空格? 2. 如何设置Vim的tabstop和shiftwidth? 3. Vim中如何只对选中的行进行空格替换? 4. 如何避免Vim在保存文件时将制表符转换为空格?</think>在 Vim 编辑器中,将连续的空格替换为制表符(Tab)可以通过以下步骤实现: ### 方法 1:使用替换命令(推荐) ```vim " 将连续 4 个空格替换为一个制表符(根据你的 tabstop 设置调整数字) :%s/ /\t/g ``` - **说明**: - `%s`:全局替换(所有行) - ` `:匹配 4 个连续空格(按空格键输入) - `\t`:替换为制表符 - `g`:替换行内所有匹配项 - **示例**: ```vim :%s/ /\t/g " 将每 8 个空格替换为一个制表符 ``` ### 方法 2:动态适配当前 tabstop 设置 ```vim " 自动根据当前 tabstop 值替换 :execute '%s/\v^ {'.&ts.'}/\t/g' ``` - **说明**: - `&ts`:获取当前 `tabstop` 值(如 4 或 2) - 例如 `tabstop=4` 时,命令等价于 `:%s/ /\t/g` ### 方法 3:保留缩进对齐(处理非整数倍空格) ```vim " 将行首空格转换为制表符+空格(保持缩进宽度) :%s/^ \+/\=repeat('\t', len(submatch(0))/&ts).repeat(' ', len(submatch(0))%&ts)/g ``` - **说明**: - 例如 5 个空格 → 1 个制表符(4 空格宽度)+ 1 个空格 - 兼容非 `tabstop` 整数倍的缩进 --- ### 关键注意事项 1. **查看当前 tabstop**: ```vim :set tabstop? " 显示当前值(默认通常为 8) ``` 2. **设置 tabstop**(如改为 4): ```vim :set tabstop=4 " 设置制表符宽度为 4 空格 ``` 3. **仅替换行首空格**(避免破坏文本内容): ```vim " 只替换行首的连续空格 :%s/^ \+/\t/g ``` 4. **可视化模式选区替换**: - 按 `V` 选择行 → 输入 `:s/ /\t/g` --- ### 示例演示 假设原始文本(`·` 表示空格): ``` ····print("Hello··World") // 4 个空格缩进 ··if true:··············· // 2 个空格 + 20 个空格 ``` 执行 `:%s/ /\t/g` 后: ``` → print("Hello··World") // 制表符替换 ··if true:··············· // 未被替换(非 4 的倍数) ``` --- ### 常见问题解决 **问题**:替换后对齐错乱? **方案**:确保 `tabstop` 和替换空格数一致,检查混合空格/制表符: ```vim :set list " 显示不可见字符(空格为·,制表符为→) ``` **问题**:如何批量转换整个项目? **方案**:用 `argdo` 处理多个文件: ```vim :args **/*.py " 加载所有.py文件 :argdo %s/ /\t/gc | w " 替换并保存(加 c 确认) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值