First ruby code, need hint on iterator

G

Gerr

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
 
L

Leslie Viljoen

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

S Wayne

Keep a count of total characters processed, and output if that is the
same as the length of your string: (see my embedded changes)
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
 
S

Sander Land

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
 
G

Gerr

Sander Land said:
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
:)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top