From: "Mauricio Fernández" Date: 2004-03-07T03:45:34+09:00 Subject: Re: The opposite of .succ! (though it still may) On Fri, Mar 05, 2004 at 06:09:43PM +0900, illocutionist wrote: > # An opposite to .succ! Or, a predecessor method for String. > > # This little thing is for my own use, and entertainment. > # There are those that might recoil from by beginners drivel, but I > # need a little help... > > # I keep getting 'out of range' error no matter what I try > # when "a".pred! > > class String > > def pred! > begin > # get the ascii value of the last element in string and decrement it... > self[self.size - 1] = (self[self.size - 1] - 1) > > if self[self.size - 1] == 96 # 'a' is the last char we want > self.chop! # when 'a'.pred! .chop char > self[self.size - 1] = 122 # set new last element to 'z' > end > return self > end while self.size > 0 # hmmmm... > end > end >> "abcd".my_pred_alpha => "abcc" >> "abcd".my_succ_alpha => "abce" >> "z".my_succ_alpha => "00" >> "00".my_pred_alpha => "z" batsman@tux-chan:/tmp$ ruby /tmp/yy.rb Loaded suite /tmp/yy Started ..... Finished in 1.525721 seconds. 5 tests, 20011 assertions, 0 failures, 0 errors class String ALPHA = [('0'..'9'), ('A'..'Z'), ('a'..'z')]. inject([]){|a,b| a + b.to_a}.map{|x| x[0]} def my_succ_alpha vals = self.unpack("C*") carry = (vals.size-1).downto(0) do |idx| if (i = ALPHA.index(vals[idx])) < ALPHA.size - 1 vals[idx] = ALPHA[i+1] break false else vals[idx] = ALPHA[0] end end vals.unshift(ALPHA[0]) if carry vals.pack("C*") end def my_pred_alpha # breaks for "0" vals = self.unpack("C*") carry = (vals.size-1).downto(0) do |idx| if (i = ALPHA.index(vals[idx])) > 0 vals[idx] = ALPHA[i-1] break false else vals[idx] = ALPHA[-1] end end vals.shift if carry vals.pack("C*") end def my_succ # just operating on byte values vals = self.unpack("C*") carry = (vals.size-1).downto(0) do |idx| if vals[idx] < 255 vals[idx] += 1 break false else vals[idx] = 0 end end vals.unshift(0) if carry vals.pack("C*") end def my_pred # 'reverse' of my_succ vals = self.unpack("C*") carry = (vals.size-1).downto(0) do |idx| if vals[idx] > 0 vals[idx] -= 1 break false else vals[idx] = 255 end end vals.shift if carry vals.pack("C*") end end require 'test/unit' class TC_my_succ < Test::Unit::TestCase def arr_succ(a) a.pack("C*").my_succ.unpack("C*") end def arr_pred(a) a.pack("C*").my_pred.unpack("C*") end def test_rand 5000.times do txt = (0..rand(20)).map{rand(255)}.pack("C*") assert_equal(txt, txt.my_succ.my_pred) assert_equal(txt, txt.my_pred.my_succ) end end def test_rand_alpha 5000.times do txt = (0..rand(20)).inject("") do |a,b| a << String::ALPHA[rand(String::ALPHA.size)] end next if txt == "0" # my_pred_alpha is undefined assert_equal(txt, txt.my_succ_alpha.my_pred_alpha) assert_equal(txt, txt.my_pred_alpha.my_succ_alpha) end end def test_my_pred_alpha assert_equal("aa", "ab".my_pred_alpha) assert_equal("aZ", "aa".my_pred_alpha) assert_equal("z", "00".my_pred_alpha) assert_equal("0", "1".my_pred_alpha) assert_equal("00", "01".my_pred_alpha) assert_equal("9", "A".my_pred_alpha) end def test_my_succ assert_equal("ab", "aa".my_succ) assert_equal("a:", "a9".my_succ) assert_equal([0, 0], arr_succ([255])) assert_equal([?b, 0], arr_succ([?a, 255])) end def test_my_pred assert_equal("aa", "ab".my_pred) assert_equal("a9", "a:".my_pred) assert_equal([0, 255], arr_pred([1,0])) assert_equal([255], arr_pred([0,0])) assert_equal([?a, 255], arr_pred([?b, 0])) end end -- Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com *** PUBLIC flooding detected from erikyyy THAT's an erik, pholx.... ;) -- Seen on #LinuxGER