[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

First ruby code, need hint on iterator

Gerr

7/17/2006 12:40:00 PM


Hello,

Consider the following code which generates a hexdump of a string:

----------------------------------------------------------------------

#!/usr/bin/ruby

module Dump

def hexdump

x = 0
offset = 0
hex = ""
str = ""
out = ""

each_byte { |c|

x = x + 1

hex << sprintf("%02x ", c)
hex << "- " if(x == 8)
str << ((c >= 32 && c<=127) ? c.to_i.chr : ".")

if(x == 16)
out << sprintf("%08x: %-50s %s\n", offset, hex, str)
x = 0
hex = ""
str = ""
offset = offset + 16
end
}

out << "\n"

return out
end
end


l = $stdin.read(10000)
l.extend Dump
print l.hexdump

----------------------------------------------------------------------

This program has a serious flaw: only if 16 bytes are collected from the input,
a new line with hex codes is printed. If the input string has a length that is
not a multiple of 16, the remaining bytes will not be handled.

A solution would be to duplicate the line

out << sprintf("%08x: %-50s %s\n", offset, hex, str)

somewhere at the end of the loop, so that any remaining buffers are printed.
This forces me to duplicate code, though, which is not what I want.

The obvious solution for me would be to change the line

if(x == 16)

to something like

if((x == 16) || (c.is_the_last_element_from_the_set))


The problem is in the fictional thingy 'is_the_last_element_from_the set',
which I believe is not available.

What would be the idiomatic solution for this in Ruby ? Any other comments on
the code are welcome as well, ofcourse

Thank you


4 Answers

Leslie Viljoen

7/17/2006 2:55:00 PM

0

> This program has a serious flaw: only if 16 bytes are collected from the input,
> a new line with hex codes is printed. If the input string has a length that is
> not a multiple of 16, the remaining bytes will not be handled.
>
> A solution would be to duplicate the line
>
> out << sprintf("%08x: %-50s %s\n", offset, hex, str)

I think it's ok to duplicate a single line. If you are worried about
the two lines
getting out of sync, put the line in a function:

def printHex(out, offset, hex, str)
out << sprintf("%08x: %-50s %s\n", offset, hex, str)
end

S Wayne

7/17/2006 2:56:00 PM

0

Keep a count of total characters processed, and output if that is the
same as the length of your string: (see my embedded changes)

Gerr wrote:
> Hello,
>
> Consider the following code which generates a hexdump of a string:
>
> ----------------------------------------------------------------------
>
> #!/usr/bin/ruby
>
> module Dump
>
> def hexdump
>
> x = 0
num_chars = 0
> offset = 0
> hex = ""
> str = ""
> out = ""
>
> each_byte { |c|
>
> x = x + 1
num_chars += 1
>
> hex << sprintf("%02x ", c)
> hex << "- " if(x == 8)
> str << ((c >= 32 && c<=127) ? c.to_i.chr : ".")
>
if(x == 16) || num_chars >= length
> out << sprintf("%08x: %-50s %s\n", offset, hex, str)
> x = 0
> hex = ""
> str = ""
> offset = offset + 16
> end
> }
>
> out << "\n"
>
> return out
> end
> end
>
>
> l = $stdin.read(10000)
> l.extend Dump
> print l.hexdump
>

Sander Land

7/17/2006 6:04:00 PM

0

On 7/17/06, Gerr <gerald@frobble.com> wrote:
> Hello,
>
> Consider the following code which generates a hexdump of a string:
> ...
> What would be the idiomatic solution for this in Ruby ? Any other comments on
> the code are welcome as well, ofcourse

If you want to do things with 16 bytes at a time, you might as well
process them in groups of 16:

require 'enumerator'
module Dump
def hexdump
offset = 0
out = ''
split('').each_slice(16) {|chars|
hc = chars.map{|c| "%02x " % c[0] }
hex = hc[0..7] << '- ' << hc[8..15]
str = chars.map{|c| (c[0] >= 32 && c[0] <= 127) ? c : "." }
out << sprintf("%08x: %-50s %s\n", offset, hex, str)
offset += 16
}
return out;
end
end

or even:

module Dump
def hexdump
offset = -16
split('').enum_slice(16).map {|chars|
hc = chars.map{|c| "%02x " % c[0] }
hex = hc[0..7] << '- ' << hc[8..15]
str = chars.map{|c| (c[0] >= 32 && c[0] <= 127) ? c : "." }
sprintf("%08x: %-50s %s\n", offset += 16, hex, str)
}.join
end
end

Gerr

7/17/2006 7:46:00 PM

0

Sander Land <sander.land@gmail.com> wrote:
> On 7/17/06, Gerr <gerald@frobble.com> wrote:
>> Hello,
>>
>> Consider the following code which generates a hexdump of a string:
>> ...
>> What would be the idiomatic solution for this in Ruby ? Any other comments on
>> the code are welcome as well, ofcourse
>
> If you want to do things with 16 bytes at a time, you might as well
> process them in groups of 16:
>
> require 'enumerator'
> module Dump
> def hexdump
> offset = 0
> out = ''
> split('').each_slice(16) {|chars|
> hc = chars.map{|c| "%02x " % c[0] }
> hex = hc[0..7] << '- ' << hc[8..15]
> str = chars.map{|c| (c[0] >= 32 && c[0] <= 127) ? c : "." }
> out << sprintf("%08x: %-50s %s\n", offset, hex, str)
> offset += 16
> }
> return out;
> end
> end

Delightful ! It's hard to think outside the box if you mainly have been
programming C for 20 years...

Thank you very much, I will learn a *lot* from this newsgroup, I'm sure
:)