tags:

views:

147

answers:

6

I wanted to detab my source files. (Please, no flame about WHY I wanted to detab my sources. That's not the point :-) I couldn't find a utility to do that. Eclipse didn't do it for me, so I implemented my own.

I couldn't fit it into a one liner (-e) program. I came with the following, which did the job just fine.

while( <> )
{
    while( /\t/ ) {
        s/^(([^\t]{4})*)\t/$1    /;
        s/^((([^\t]{4})*)[^\t]{1})\t/$1   /;
        s/^((([^\t]{4})*)[^\t]{2})\t/$1  /;
        s/^((([^\t]{4})*)[^\t]{3})\t/$1 /;
    }
    print;
}

However, it makes me wonder if Perl - the champion language of processing text - is the right tool. The code doesn't seem very elegant. If I had to detab source that assume tab=8 spaces, the code would look even worse.

Specifically because I can think of a deterministic state machine with only 4 states to do the job.

I have a feeling that a more elegant solution exists. Am I missing a Perl idiom? In the spirit of TIMTOWTDI I'm curious about the other ways to do it.

u.

+6  A: 

What ever happened to the old Unix program "expand"? I used to use that all the time.

Paul Tomblin
+1 I'm not sure if the question was rhetorical, but on my Debian/Ubuntu systems it's in the 'coreutils' package.
Grant McLean
+5  A: 

I remember a detabify script from one of the O'Reilly books, but I can't seem to find a link now.

I have had to solve this problem as well, and I settled on this concise solution to detabify a line:

1 while $line =~ s/\t/" " x ($tablength - ($-[0] % $tablength))/e ;

In this regular expression $-[0] is the length of the "pre-matched" portion of the line -- the number of characters before the tab character.


As a one-liner:

perl -pe '1 while s/\t/" "x(4-($-[0]%4))/e' input
mobrule
Nice, I wasn't familiar with the @+ and @- arrays. Thanks. However, your answer if off by one. The correct answer is: while s/\t/ " " x ( 4 - ($-[0]%4) ) / e
Uri
Thanks Uri, that was a good catch. Maybe I should have tried harder to use an existing module.
mobrule
+1  A: 

I do this in vim with:

:%s/^V^I/    /g

(That's a literal ^V followed by a literal tab), and then :%gq to fix incorrect spacing. Perl is overkill.

Ether
+3  A: 

Whenever I want to expand tabs, I use Text::Tabs.

toolic
+3  A: 

This can be easily done in vim:

:set expandtab
:retab

http://vim.wikia.com/wiki/Converting_tabs_to_spaces

eugene y
+2  A: 

Can't let vi be all alone here. Emacs:

M-x tabify
M-x untabify
Pedro Silva