Expandtabs

The methods for expanding tabs in the Ruby FAQ don’t seem to work.

http://www.rubygarden.org/iowa/faqtotum/abVzk6Z1cXs2/ef/1.17.13

I’ve attached my test script.

begin 666 expandtabs.rb
M9&5F(&UE=&AO9#$H82D-“B @,2!W:&EL92!A+G-U8B$H+RA>6UY<=%TJ5QT
M
%QTBDO7LD,2LG(”<J*#@M)#$N<VEZ924XS@J)#(N<VEZ92E]#0H@(&$-
M"F5N9 T
#0ID968@;65T:&]D,BAA0T(" Q(’=H:6QE(&$N<W5B(2@O7’0H
M7’0J2\I>R<@)RHH."TD?BYB96=I;B@P24XS@J)#$N<VEZ92E]#0H@(&$-
M"F5N9 T
#0ID968@;65T:&]D,RAA0T("!A+F=S=6(A*"\H6UY<=%U[.‘TI
M?“A;7EQT72HI7’0O;BE[6R0K72YP86-K*”)!."(I?0T*("!A#0IE;F0-"@T*
M9&5F(’!R:6YT;&XH<RD-“B @<’)I;G0@<RP@(EQN(@T96YD#0H-“G-T<FEN
M9R ](”(B#0HH,"XN,3 I+F5A8V@@>WQN? T
(”!S=’)I;F<@/#P@(F)L86A<
M="(@R H(B B("H@;BD@R B8FQA:%QN(@T?0T#0IP<FEN=" B+2T@;W)I
M9VEN86P@<W1R:6YG7&XB#0IP<FEN=&QN*’-T<FEN9RD-"@T*<’)I;G0@(BTM
M(&UE=&AO9#%<;B(-“G!R:6YT;&XH;65T:&]D,2AS=’)I;F<N8VQO;F4I0T
M#0IP<FEN=” B+2T@;65T:&]D,EQN(@T*<’)I;G1L;BAM971H;V0R*’-T<FEN
M9RYC;&]N92DI#0H-“G!R:6YT(”(M+2!M971H;V0S7&XB#0IP<FEN=&QN*&UE
M=&AO9#,H<W1R:6YG+F-L;VYE2D-"@T<’)I;G0@(BTM(&]R:6=I;F%L(’-T
:<FEN9UQN(@T*<’)I;G1L;BAS=’)I;F<I#0H
end

Saluton!

  • Steven Shaw, 2003-05-30, 21:05 UTC:

The methods for expanding tabs in the Ruby FAQ don’t seem to work.

def method1(a)
1 while a.sub!(/([1])\t(\t)/){$1+’ '(8-$1.size%8+8$2.size)}
a
end

def method2(a)
1 while a.sub!(/\t(\t*)/){’ '(8-$~.begin(0)%8+8$1.size)}
a
end

def method3(a)
a.gsub!(/([^\t]{8})|([^\t]*)\t/n){[$+].pack(“A8”)}
a
end

def println(s)
print s, “\n”
end

string = “”
(0…10).each {|n|
string << “blah\t” + (" " * n) + “blah\n”
}

println(method1(string.clone))
println(method2(string.clone))
println(method3(string.clone))

I did already answer that in a PM. The above works correct but does
not have the intended result. The problem is that the sample string
does contain “\n” characters.

The easiest solution would be using

string.split(“\n”).each{|x| println(method1(x))}
string.split(“\n”).each{|x| println(method2(x))}
string.split(“\n”).each{|x| println(method3(x))}

in place of the given calls of println. Nevertheless it would be
better to reset the length counting for each “\n”. The following is a
quick’n’dirty hack that does this in a way that is far from optimal.

def method4(a)
b = ‘’
l = 1
0.upto(a.length) { |i|
case a[i]
when 9
b += ’ ’
l += 1
while l % 8 != 0
b += ’ ’
l += 1
end
when 10
b += a[i…i]
l = 1
else
b += a[i…i]
l += 1
end
}
return b
end

A shorter solution is:

def method1(a)
a.split(“\n”).each {|b|
1 while b.sub!(/([2])\t(\t)/){$1+’ '(8-$1.size%8+8$2.size)}
b
}.join(“\n”)
end

The equivalents for method2 and method3 are obvious. Does anybody
have a better solution that does not require splitting and re-joining
(which is time-consuming)?

Gis,

Josef ‘Jupp’ Schugt

···


e-mails that do not contain plain text, are larger than 50 KiB, are
unsolicited, or contain binarys are ignored unless payment from your
side or technical reasons give rise to a non-standard treatment.
Schroedinger’s cat is not alive.


  1. ^\t ↩︎

  2. ^\t ↩︎

How about this:

def expand_tabs(data, indent=8)
x = 0
i = 0
while i < data.length
case data[i]
when 9
add = indent - (x % indent)
data[i…i] = ‘.’*add
x += add
i += add
when 10
x = 0
i += 1
else
x += 1
i += 1
end
end
data
end
text = <<TXT
a
1 b
12 4 c
123 d
e
f
g
TXT
expand_tabs(text)
puts text

···

On Sun, 01 Jun 2003 05:04:51 +0900, Josef ‘Jupp’ Schugt wrote:

The equivalents for method2 and method3 are obvious. Does anybody
have a better solution that does not require splitting and re-joining
(which is time-consuming)?


Simon Strandgaard

When expanding a tab I guess you are actually interested in the number of
characters since the previous tab or newline, so how about something like:

def expand_tabs(data, indent=8)
data.gsub(/([^\t\n]*)\t/) {
$1 + " " * (indent - ($1.size % indent))
}
end

Anybody have a test suite?

Regards,

Brian.

Anybody have a test suite?

No but here’s the test script I’ve been using. It has all the different
methods from the FAQ and the ones posted here. Your method works on my test
data.

def method1(s)
def sub_line(a)
1 while a.sub!(/([1])\t(\t)/){$1+’ '(8-$1.size%8+8$2.size)}
a
end

result = “”
s.each { |line| result << sub_line(line) }
result
end

def method2(s)
def sub_line(a)
1 while a.sub!(/\t(\t*)/){’ '(8-$~.begin(0)%8+8$1.size)}
a
end

result = “”
s.each { | line | result << sub_line(line) }
result
end

def method3(s)
def sub_line(a)
a.gsub!(/([^\t]{8})|([^\t]*)\t/n){[$+].pack(“A8”)}
a
end

result = “”
s.each { | line | result << sub_line(line) }
result
end

def method4(a)
b = ‘’
l = 1
0.upto(a.length) { |i|
case a[i]
when 9
b += ’ ’
l += 1
while l % 8 != 0
b += ’ ’
l += 1
end
when 10
b += a[i…i]
l = 1
else
b += a[i…i]
l += 1
end
}
return b
end

def method5(data, indent=8)
x = 0
i = 0
while i < data.length
case data[i]
when 9
add = indent - (x % indent)
data[i…i] = ’ '*add
x += add
i += add
when 10
x = 0
i += 1
else
x += 1
i += 1
end
end
data
end

def method6(data, indent=8)
data.gsub(/([^\t\n]*)\t/) {
$1 + " " * (indent - ($1.size % indent))
}
end

def println(*s)
print s, “\n”
end

string = “”
(0…10).each {|n|
string << “blah\t” + (" " * n) + “blah\n”
}
(0…10).each {|n|
string << “blah” + (" " * n) + “\tblah\n”
}

println “-- original string”
println(string)

construct correct answer from method1

$correct = method1(string.clone)

def test_it(result)
print result
if result == $correct
println “result is correct”
else
println “result in incorrect”
end
println
end

println “-- method2”
test_it(method2(string.clone))

println “-- method3”
test_it(method3(string.clone))

println “-- method4”
test_it(method4(string.clone))

println “-- method5”
test_it(method5(string.clone))

println “-- method6”
test_it(method6(string.clone))

Sorry about my code. I’m just learning Ruby. What’s the opposite of split?


  1. ^\t ↩︎

Saluton!

  • Steven Shaw; 2003-06-02, 11:02 UTC:

What’s the opposite of split?

join:

ruby -e ‘p [“a”, “b”].join’
“ab”

ruby -e ‘p [“a”, “b”].join(“\n”)’
“a\nb”

ruby -e ‘$, = “\n”;p [“a”, “b”].join’
“a\nb”

HTH

Gis,

Josef ‘Jupp’ Schugt

···


e-mails that do not contain plain text, are larger than 50 KiB, are
unsolicited, or contain binarys are ignored unless payment from your
side or technical reasons give rise to a non-standard treatment.
Schroedinger’s cat is not alive.