Here’s my solution.
Usage : scramble.rb <text_file>
I made 3 attempts.
-
print ARGF.read.gsub!(/\B[a-z]+\B/) {|x| x.split(’’).sort_by{rand}.join}
Here I use gsub to find all the words. Use split to convert strings into
arrays. And then use the sort_by{rand} to scramble the arrays. And
finally
use join to convert the array back to a string.
I’m assuming that words don’t have upper case letters in the middle, so
that
I can get away with [a-z].
-
print ARGF.read.gsub!(/\B[a-z]+\B/) {|x| x.unpack
(‘c*’).sort_by{rand}.pack(‘c*’)}
I found this method of converting strings to and from arrays to be
faster.
I’m not sure what the standard idiom for doing this is. But, I’m sure
I’ll
learn after seeing other people’s solutions 
3 If sort_by{rand} does what I think it does, it probably has a bias
when
the rand function returns the same value. So, this is my third
implementation:
print ARGF.read.gsub!(/\B[a-z]+\B/) {|x|
x.length.times {|i|
j = rand(i+1)
x[j], x[i] = x[i] , x[j]
}
x
}
Basically, this is an implementation of scrambling that uses swaps. I
remember this method for scrambling from way back, but I can’t seem to
find
a good reference for it at the moment.
I also figured that this method would be faster since it is linear,
while
the sorts are n log(n) (n = length of the word)
To by surprise, I found this method to actually be slower for any normal
text. One possible explanation is that when words are relatively short
you
don’t gain much from the n vs. nlogn difference, and you lose because
while
this method always has n swaps, sorting may have less.
In order to see any performance benefit from the 3rd method I had to
make up
some horrifically long words which aren’t terribly likely in the
English
language (maybe I should have tried German :)).
Himadri