0

After reading https://stackoverflow.com/questions/7338794/vim-regex-replace-with-n-characters, I've known how to replace tabs by spaces:

:%s/^\v(\t)*/\=repeat(repeat(' ',4),strlen(submatch(0)))/g

The command above allows me to replace n tabs at the beginning of each line with n four-spaces.

Now I want to inverse it: replace n four-spaces with n tabs, I think the command should be :%s/^\v( )*/\=repeat("\t",strlen(submatch(0)))/g, but it doesn't work: if there is one four-space, it will be replaced by four tabs after executing the command.

Besides, is it possible to get the length of tab of vim so that I can make the command as below?

:%s/^\v(\t)*/\=repeat(repeat(' ',getSizeOfTab()),strlen(submatch(0)))/g

ATTENTION: I only want to replace the spaces at the beginning of each line.

  • @Mass \w? I only want to replace the spaces at the beginning of each line. :%s/^ \{4}/\t/g can only replace the first 4 spaces, if there are 8 spaces, it won't work. – Yves May 10 '18 at 3:29
  • 1
    Sorry, no idea what I was thinking. check out s/\(^\s*\)\@<= \{4}/\t/g – Mass May 10 '18 at 3:39
  • @Mass I think you can make this as an answer and explain how it works, I ll accept it. I don't understand what @<= is. – Yves May 10 '18 at 3:50
  • @Yves See :help /\@<= – Rich May 10 '18 at 8:36
  • Doesnt :retab already solve most of this problem? – D. Ben Knoble May 10 '18 at 13:58
2

I think you want a simple:

%s/\s\{4\}/\t/g

that matches 4 spaces and replaces them by a single tab.

If you want it to only appy to the beginning of the line, this should work:

%s/\(^\s*\)\@<=\(\s\{4\}\)/\t/g

That uses a zero-width assertion to make sure it always matches Spaces at the beginning of a line.

The other question: If you want to know the length of a tab you can access the 'tabstop' setting. However, since it usually depends on the position where the tab is on the screen, you might want to check the strdisplaywidth() function.

  • 1
    I think it would be better to use plain space characters rather than \s. You don't want to replace 4 tabs with a single tab. (And yes, I've worked with codebases where this might actually make a difference ;) ) – Rich May 10 '18 at 8:50
1

The problem with the command you've already tried is that you're calculating the number of tabs to add by using the length of the entire match. So if you have 4 spaces, which has a length of 4, you use 4 tabs. You can fix this simply by dividing the length by 4. In order not to confuse the / division operator with the / characters used for separating the :substitute command, you will need to use a different character for the latter (See :help E146):

 :%s@^\v( )+@\=repeat("\t",strlen(submatch(0))/4)@g
           ^                                  ^^

N.B. I made one other change to your command: switching the * for a +. There's no need to replace no spaces with no tabs!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.