# File scanf.rb, line 44
    def initialize(str)
      @spec_string = str

      h = '[A-Fa-f0-9]'

      @re_string, @handler = 
	case @spec_string

	  # %[[:...:]]
	when /%\*?(\[\[:[a-z]+:\]\])/
	  [ "(#{$1}+)", :extract_plain ]

	  # %5[[:...:]]
	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 ]

	  # %i
	when /%\*?i/
	  [ "([-+]?(?:(?:0[0-7]+)|(?:0[Xx]#{h}+)|(?:[1-9]\\d+)))", :extract_integer ]

	  # %5i
	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 ]

	  # %d, %u
	when /%\*?[du]/
	  [ '([-+]?\d+)', :extract_decimal ]

	  # %5d, %5u
	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 ]

	  # %x
	when /%\*?[Xx]/
	  [ "([-+]?(?:0[Xx])?#{h}+)", :extract_hex ]

	  # %5x
	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 ]

	  # %o
	when /%\*?o/
	  [ '([-+]?[0-7]+)', :extract_octal ]

	  # %5o
	when /%\*?(\d+)o/
	  [ "([-+][0-7]{1,#{$1.to_i-1}}|[0-7]{1,#{$1}})", :extract_octal ]

	  # %f
	when /%\*?f/
	  [ '([-+]?((\d+(?>(?=[^\d.]|$)))|(\d*(\.(\d*([eE][-+]?\d+)?)))))', :extract_float ]

	  # %5f
	when /%\*?(\d+)f/
	  [ "(\\S{1,#{$1}})", :extract_float ]

	  # %5s
	when /%\*?(\d+)s/
	  [ "(\\S{1,#{$1}})", :extract_plain ]

	  # %s
	when /%\*?s/
	  [ '(\S+)', :extract_plain ]

	  # %c
	when /\s%\*?c/
	  [ "\\s*(.)", :extract_plain ]

	  # %c
	when /%\*?c/
	  [ "(.)", :extract_plain ]

	  # %5c (whitespace issues are handled by the count_*_space? methods)
	when /%\*?(\d+)c/
	  [ "(.{1,#{$1}})", :extract_plain ]

	  # %%
	when /%%/
	  [ '(\s*%)', :nil_proc ]

	  # literal characters
	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)
      s = str.dup
      s.sub!(/\A\s+/,'') unless count_space?
      res = to_re.match(s)
      if res
	@conversion = send(@handler, res[1])
	@matched_string = @matched_item.to_s
      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 || 0
    end

    def mid_match?
      cc_no_width    =   letter == '[' && width.zero?
      c_or_cc_width  =   (letter == 'c' || letter == '[') &&! width.zero?
      c_or_cc_open   =   c_or_cc_width && (matched_string.size < width)
      
      return c_or_cc_open || cc_no_width
    end
    
  end