class Scanf::FormatString::IO

Public Instance Methods

block_scanf(str) { |current| ... } click to toggle source
# File lib/scanf.rb, line 682
  def block_scanf(str)
    final = []
# Sub-ideal, since another FS gets created in scanf.
# But used here to determine the number of specifiers.
    fstr = Scanf::FormatString.new(str)
    last_spec = fstr.last_spec
    begin
      current = scanf(str)
      break if current.empty?
      final.push(yield(current))
    end until eof || fstr.last_spec_tried == last_spec
    return final
  end
end
scanf(str) { |current_match| ... } click to toggle source

Scans the current string until the match is exhausted, yielding each match as it is encountered in the string. A block is not necessary though, as the results will simply be aggregated into the final array.

"123 456".block_scanf("%d")
# => [123, 456]

If a block is given, the value from that is returned from the yield is added to an output array.

"123 456".block_scanf("%d") do |digit,| # the ',' unpacks the Array
  digit + 100
end
# => [223, 556]

See Scanf for details on creating a format string.

You will need to require 'scanf' to use #scanf.

# File lib/scanf.rb, line 614
  def scanf(str,&b) #:yield: current_match
    return block_scanf(str,&b) if b
    return [] unless str.size > 0

    start_position = pos rescue 0
    matched_so_far = 0
    source_buffer = ""
    result_buffer = []
    final_result = []

    fstr = Scanf::FormatString.new(str)

    loop do
      if eof || (tty? &&! fstr.match(source_buffer))
        final_result.concat(result_buffer)
        break
      end

      source_buffer << gets

      current_match = fstr.match(source_buffer)

      spec = fstr.last_spec_tried

      if spec.matched
        if spec.mid_match?
          result_buffer.replace(current_match)
          next
        end

      elsif (fstr.matched_count == fstr.spec_count - 1)
        if /\A\s*\z/.match(fstr.string_left)
          break if spec.count_space?
          result_buffer.replace(current_match)
          next
        end
      end

      final_result.concat(current_match)

      matched_so_far += source_buffer.size
      source_buffer.replace(fstr.string_left)
      matched_so_far -= source_buffer.size
      break if fstr.last_spec
      fstr.prune
    end

    begin
      seek(start_position + matched_so_far, IO::SEEK_SET)
    rescue Errno::ESPIPE
    end

    soak_up_spaces if fstr.last_spec && fstr.space

    return final_result
  end

  private

  def soak_up_spaces
    c = getc
    ungetc(c) if c
    until eof ||! c || /\S/.match(c.chr)
      c = getc
    end
    ungetc(c) if (c && /\S/.match(c.chr))
  end

  def block_scanf(str)
    final = []
# Sub-ideal, since another FS gets created in scanf.
# But used here to determine the number of specifiers.
    fstr = Scanf::FormatString.new(str)
    last_spec = fstr.last_spec
    begin
      current = scanf(str)
      break if current.empty?
      final.push(yield(current))
    end until eof || fstr.last_spec_tried == last_spec
    return final
  end
end

class String

  # :section: scanf
  #
  # You will need to require 'scanf' to use these methods

  # Scans the current string. If a block is given, it
  # functions exactly like block_scanf.
  #
  #   arr = "123 456".scanf("%d%d")
  #   # => [123, 456]
  #
  #   require 'pp'
  #
  #   "this 123 read that 456 other".scanf("%s%d%s") {|m| pp m}
  #
  #   # ["this", 123, "read"]
  #   # ["that", 456, "other"]
  #   # => [["this", 123, "read"], ["that", 456, "other"]]
  #
  # See Scanf for details on creating a format string.
  #
  # You will need to require 'scanf' to use String#scanf
  def scanf(fstr,&b) #:yield: current_match
    if b
      block_scanf(fstr,&b)
    else
      fs =
        if fstr.is_a? Scanf::FormatString
          fstr
        else
          Scanf::FormatString.new(fstr)
        end
      fs.match(self)
    end
  end

  # Scans the current string until the match is exhausted
  # yielding each match as it is encountered in the string.
  # A block is not necessary as the results will simply
  # be aggregated into the final array.
  #
  #   "123 456".block_scanf("%d")
  #   # => [123, 456]
  #
  # If a block is given, the value from that is returned from
  # the yield is added to an output array.
  #
  #   "123 456".block_scanf("%d) do |digit,| # the ',' unpacks the Array
  #     digit + 100
  #   end
  #   # => [223, 556]
  #
  # See Scanf for details on creating a format string.
  #
  # You will need to require 'scanf' to use String#block_scanf
  def block_scanf(fstr) #:yield: current_match
    fs = Scanf::FormatString.new(fstr)
    str = self.dup
    final = []
    begin
      current = str.scanf(fs)
      final.push(yield(current)) unless current.empty?
      str = fs.string_left
    end until current.empty? || str.empty?
    return final
  end
end

module Kernel
  private
  # Scans STDIN for data matching +format+.  See IO#scanf for details.
  #
  # See Scanf for details on creating a format string.
  #
  # You will need to require 'scanf' to use Kernel#scanf.
  def scanf(format, &b) #:doc:
    STDIN.scanf(format ,&b)
  end
soak_up_spaces() click to toggle source
# File lib/scanf.rb, line 673
def soak_up_spaces
  c = getc
  ungetc(c) if c
  until eof ||! c || /\S/.match(c.chr)
    c = getc
  end
  ungetc(c) if (c && /\S/.match(c.chr))
end