簡體   English   中英

Ruby:使用StringScanner會導致無限循環

[英]Ruby: Using StringScanner causes infinite loop

我有以下課程:

require 'strscan'

class ConfParser
  include Enumerable

  class Error < StandardError; end
  VERSION = '0.0.1'
  SECTION_REGEX = /^\[       # Opening bracket
                   ([^\]]+)  # Section name
                   \]$       # Closing bracket
                 /x
  PARAMETER_REGEX = /^\s*([^:]+)  # Option
                      :
                      (.*?)$      # Value
                    /x

  attr_accessor :filename, :sections

  CONFIG_DIRECTORY = "./config"
  ENCODING = "UTF-8"

  def self.read(filename, opts = {})
    new(opts.merge(:filename => filename))
  end

  def initialize(opts = {})
    @filename = opts.fetch(:filename)
    @separator = opts.fetch(:separator, ":")
    @file = "#{CONFIG_DIRECTORY}/#{@filename}"
    @content = nil
    @config = Hash.new { |h,k| h[k] = Hash.new }

    load
  end

  def load
    raise_error("First line of config file contain be blank") if first_line_empty?

    f = File.open(@file, 'r')
    @content = f.read
    parse!

    ensure
      f.close if f && !f.closed?
  end

  def sections
    @config.keys
  end

  def [](section)
    return nil if section.nil?

    @config[section.to_s]
  end

  def []=( section, value )
    @config[section.to_s] = value
  end

  private

    def parse!
      @_section = nil
      @_current_line = nil
      property = ''
      string = ''

      @config.clear

      scanner = StringScanner.new(@content)

      until scanner.eos?
        @_current_line = scanner.check(%r/\A.*$/) if scanner.bol?

        if scanner.scan(SECTION_REGEX)
          @_section = @config[scanner[1]]
        else
          tmp = scanner.scan_until(%r/([\n"#{@param}#{@comment}] | \z | \\[\[\]#{@param}#{@comment}"])/mx)
          raise_error if tmp.nil?

          len = scanner[1].length
          tmp.slice!(tmp.length - len, len)

          scanner.pos = scanner.pos - len
          string << tmp
        end
      end

      process_property(property, string)

      logger @config
    end

    def process_property( property, value )
      value.chomp!
      return if property.empty? and value.empty?
      return if value.sub!(%r/\\\s*\z/, '')

      property.strip!
      value.strip!

      parse_error if property.empty?

      current_section[property.dup] = unescape_value(value.dup)

      property.slice!(0, property.length)
      value.slice!(0, value.length)

      nil
    end

    def logger log
      puts "*"*50
      puts log
      puts "*"*50
    end

    def first_line_empty?
      File.readlines(@file).first.chomp.empty?
    end

    def raise_error(msg = 'Error processing line')
      raise Error, "#{msg}: #{@_current_line}"
    end

    def current_section
      @_section ||= @config['header']
    end

end

上面的類會分析像這樣設置的文件:

[header]
project: Hello World
budget : 4.5
accessed :205

[meta data]
description : This is a tediously long description of the Hello World
  project that you are taking. Tedious isn't the right word, but
  it's the first word that comes to mind.

correction text: I meant 'moderately,' not 'tediously,' above.

[ trailer ]
budget:all out of budget.

您開始像這樣運行它:

require 'conf_parser'
cf = ConfParser.read "/path/to/conf/file"

由於某種原因當parse! 方法運行時,發生無限循環,我不知道為什么。 有什么原因會發生這種情況? 我以前從未使用過StringScanner,所以可能是我對該課程缺乏了解

冒着明顯的危險,您很可能永遠無法滿足scanner.eos? ,這反過來意味着您沒有將掃描指針推進到字符串的末尾。 因為在parse!else分支中唯一更改了scanner.pos parse! 是要減少它(即len ),這是可以理解的。 如果if分支沒有將其推進到末尾,那么您將永遠不會終止。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM