From: Daniel Schierbeck Date: 2006-07-13T05:40:10+09:00 Subject: Re: Help with a regexp Phrogz wrote: > Here's what I consider a slightly cleaner, more robust version: > > require 'strscan' > inp = "3:ab23:cat5:sheep" > s = StringScanner.new( inp ) > words = [] > until s.eos? > begin > unless digits = s.scan( /\d+(?=:)/ ) > raise "I can't find an integer followed by a colon" > end > s.pos += 1 # skip the colon we know is there > digits = digits.to_i > unless s.rest_size >= digits > raise "I ran out of characters; looking for #{digits} characters, > #{s.rest_size} left" > end > words << s.peek( digits ) > s.pos += digits > rescue RuntimeError => e > warn "Looking at #{s.rest.inspect}," > warn e.message > abort "Words found so far: #{words.inspect}" > end > end > puts "Words found: ", words > Thanks for the help! I ended up doing it slightly different (after a lot of pain, and a sneek peek at a Python script.): This is an early library that handles bencoding. Note that the error handling is pretty much non-existent at this point, and it'll break if you fart on it. class String def bencode "#{length}:#{self}" end end class Numeric def bencode "i#{floor}e" end end class Array def bencode "l#{map{|obj| obj.bencode}}e" end end class Hash def bencode "d#{map{|key, val| [key.bencode, val.bencode]}}e" end end module Bencode @filter = {:integer => /(0|-?[1-9]+\d*)e/, :string => /(0|[1-9][0-9]*):/} class << self attr_reader :map def dump(obj) obj.bencode end def load(str) decode(str, 0).first end def decode_integer(data, i) match = @filter[:integer].match(data[i..-1]) raise ArgumentError if match.nil? return Integer(match[1]), match.end(0) + i end def decode_string(data, i) match = @filter[:string].match(data[i..-1]) raise ArgumentError if match.nil? length = Integer(match[1]) offset = match.end(0) + length + i return data[(match.end(0) + i)...offset], offset end def decode_list(data, i) ary = [] while data[i..i] != "e" val, i = decode(data, i) ary << val end return ary, i + 1 end def decode_dict(data, i) hsh = {} while data[i..i] != "e" key, i = decode_string(data, i) val, i = decode(data, i) hsh[key] = val end return hsh, i + 1 end def decode(data, i) case data[i..i] when "i" decode_integer(data, i + 1) when "l" decode_list(data, i + 1) when "d" decode_dict(data, i + 1) else decode_string(data, i) end end end end Eventually I'll upload it to RubyForge. If you've got comments, bring 'em on, but remember that I only just started this today. Cheers, Daniel