The opposite of .succ! (though it still may)

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

Hi,

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

IRB can be a big help in trying out bits of code interactively…

irb --simple-prompt

x = “a”
=> “a”

let’s try the first line there…

self[self.size - 1] = (self[self.size - 1] - 1)

x[x.size - 1] = x[x.size - 1] - 1
=> 96
x
=> “`”

so far so good…

…Incidentally, that line can be written shorter,

using a negative index to index relative to the end

of the container, and -= method to decrement…

x = “a”
=> “a”
x[-1] -= 1 # same as: x[x.size - 1] = x[x.size - 1] - 1
=> 96
x
=> “`”

same result…

OK… let’s try the next line,

if self[self.size - 1] == 96

x[-1] == 96 # same thing, using simpler index
=> true

OK continuing on…

x.chop!
=> “”
x
=> “”

well we’ve chopped our lone character down to nothing…

we’re now about to try this line:

self[self.size - 1] = 122

Let’s see what self.size - 1 would be…

x.size - 1
=> -1

Hmm, so . . .

x[x.size - 1] = 122
IndexError: index -1 out of string
from (irb):13:in `=’
from (irb):13

So I guess the routine needs some logic to bail out on
a lone ‘a’ … Or bail out when the chop! reduces the
string to zero length? (Not sure what the desired
outcome is … :slight_smile:

Hope this helps,

Regards,

Bill

Hi,

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

First of all: You’re doing too much work! :smiley: there are a couple things
you an do that will make the code smaller, and even easier to read.

Take this line:
self[self.size - 1] = (self[self.size - 1] - 1)

first: when using array notation, there is an easier way to get the
last element. You can leave off the “self.size” and just have the -1
part
self[-1] = (self[-1] - 1)

next, since array notation can be used for both assignment and
retrieval, you can use “-=” :slight_smile:
self[-1] -= 1 # this decrements the last character

However, I think that there is a logic error in your code…

‘cba’.pred!
=> “cz”
‘cba’.pred!.succ!
=> “da”

shouldn’t “‘cba’.pred!.succ!” return ‘cba’?

looking at your code, I see that you are decrementing the last
character, then chopping it if it is under-valued. What you really want
to do is decrement the character to it’s left, and set the last
character to ‘z’.

if self[-1] > 97 # it’s bigger than a
self[-1] -= 1
else # it is a. look to the left.
# decrement char to left, set self[-1] to z
# unless there is no char to the left, in which case, return ‘’
end

There’s more, but I’ll leave the rest as an exercise :wink:

–Mark

···

On Mar 5, 2004, at 1:09 AM, 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

···

On Fri, Mar 05, 2004 at 06:09:43PM +0900, illocutionist wrote:


Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

*** PUBLIC flooding detected from erikyyy
THAT’s an erik, pholx… :wink:
– Seen on #LinuxGER