def initialize(str)
@spec_string = str
h = '[A-Fa-f0-9]'
@re_string, @handler =
case @spec_string
when /%\*?(\[\[:[a-z]+:\]\])/
[ "(#{$1}+)", :extract_plain ]
when /%\*?(\d+)(\[\[:[a-z]+:\]\])/
[ "(#{$2}{1,#{$1}})", :extract_plain ]
when /%\*?\[([^\]]*)\]/
yes = $1
if /^\^^/.match(yes) then no = yes[1..-1] else no = '^' + yes end
[ "([#{yes}]+)(?=[#{no}]|\\z)", :extract_plain ]
# %5[...]
when /%\*?(\d+)\[([^\]]*)\]/
yes = $2
w = $1
[ "([#{yes}]{1,#{w}})", :extract_plain ]
when /%\*?i/
[ "([-+]?(?:(?:0[0-7]+)|(?:0[Xx]#{h}+)|(?:[1-9]\\d+)))", :extract_integer ]
when /%\*?(\d+)i/
n = $1.to_i
s = "("
if n > 1 then s += "[1-9]\\d{1,#{n-1}}|" end
if n > 1 then s += "0[0-7]{1,#{n-1}}|" end
if n > 2 then s += "[-+]0[0-7]{1,#{n-2}}|" end
if n > 2 then s += "[-+][1-9]\\d{1,#{n-2}}|" end
if n > 2 then s += "0[Xx]#{h}{1,#{n-2}}|" end
if n > 3 then s += "[-+]0[Xx]#{h}{1,#{n-3}}|" end
s += "\\d"
s += ")"
[ s, :extract_integer ]
when /%\*?[du]/
[ '([-+]?\d+)', :extract_decimal ]
when /%\*?(\d+)[du]/
n = $1.to_i
s = "("
if n > 1 then s += "[-+]\\d{1,#{n-1}}|" end
s += "\\d{1,#{$1}})"
[ s, :extract_decimal ]
when /%\*?[Xx]/
[ "([-+]?(?:0[Xx])?#{h}+)", :extract_hex ]
when /%\*?(\d+)[Xx]/
n = $1.to_i
s = "("
if n > 3 then s += "[-+]0[Xx]#{h}{1,#{n-3}}|" end
if n > 2 then s += "0[Xx]#{h}{1,#{n-2}}|" end
if n > 1 then s += "[-+]#{h}{1,#{n-1}}|" end
s += "#{h}{1,#{n}}"
s += ")"
[ s, :extract_hex ]
when /%\*?o/
[ '([-+]?[0-7]+)', :extract_octal ]
when /%\*?(\d+)o/
[ "([-+][0-7]{1,#{$1.to_i-1}}|[0-7]{1,#{$1}})", :extract_octal ]
when /%\*?f/
[ '([-+]?((\d+(?>(?=[^\d.]|$)))|(\d*(\.(\d*([eE][-+]?\d+)?)))))', :extract_float ]
when /%\*?(\d+)f/
[ "(\\S{1,#{$1}})", :extract_float ]
when /%\*?(\d+)s/
[ "(\\S{1,#{$1}})", :extract_plain ]
when /%\*?s/
[ '(\S+)', :extract_plain ]
when /\s%\*?c/
[ "\\s*(.)", :extract_plain ]
when /%\*?c/
[ "(.)", :extract_plain ]
when /%\*?(\d+)c/
[ "(.{1,#{$1}})", :extract_plain ]
when /%%/
[ '(\s*%)', :nil_proc ]
else
[ "(#{Regexp.escape(@spec_string)})", :nil_proc ]
end
@re_string = '\A' + @re_string
end
def to_re
Regexp.new(@re_string,Regexp::MULTILINE)
end
def match(str)
@matched = false
s = str.dup
s.sub!(/\A\s+/,'') unless count_space?
res = to_re.match(s)
if res
@conversion = send(@handler, res[1])
@matched_string = @conversion.to_s
@matched = true
end
res
end
def letter
/%\*?\d*([a-z\[])/.match(@spec_string).to_a[1]
end
def width
w = /%\*?(\d+)/.match(@spec_string).to_a[1]
w && w.to_i
end
def mid_match?
return false unless @matched
cc_no_width = letter == '[' &&! width
c_or_cc_width = (letter == 'c' || letter == '[') && width
width_left = c_or_cc_width && (matched_string.size < width)
return width_left || cc_no_width
end
end