fparseln(3)もどき

通学路

NetBSDのfparseln(3)は、コメントや継続行を処理して一行を返す関数です。この関数、設定ファイルとかの読み込みに結構便利。
Rubyでもfparseln(3)を使いたいなと思って、fparseln(3)ぽい機能をRubyぽく実装してみました。

以下はobsoleteです。id:ha-tan:20050728を参照ください。

class IO
  def parseln(lineno = nil, delim = '\\\\#')
    esc = Regexp.escape(delim[0].chr)
    con = Regexp.escape(delim[1].chr)
    com = Regexp.escape(delim[2].chr)
    escre = /#{esc}(.)/
    conre = /(^|[^#{esc}])#{con}$/
    comre = /(^|[^#{esc}])#{com}/

    buf = ''
    while line = self.gets
      line.chomp!
      lineno += 1 unless lineno.nil?

      if line =~ comre
        line = $` + $1
        next if line.size == 0 and buf.size == 0
      end

      if line =~ conre
        buf += ($` + $1).gsub(escre, '\1')
        next
      end

      buf += line.gsub(escre, '\1')
      if lineno.nil?
        yield(buf)
      else
        yield(buf, lineno)
      end
      buf = ''
    end
  end
end

以下、使い方。入力するテキストファイルfoo.txtをこんな感じで用意して、

# comment...
aaa
bbb
ccc \
ddd

IO#parselnを以下のようにコールします。

open('foo.txt', 'r') do |file|
  file.parseln(0) do |line, lineno|
    printf "%4d: <%s>\n", lineno, line
  end
end

出力はこんな感じ。コメントと継続行がそれっぱく処理されています。

   2: <aaa>
   3: <bbb>
   5: <ccc ddd>

BUGS: オリジナルのfparseln(3)には以下の機能がありますが、上のコードでは実装していません。

  • 一行の長さの指定。
  • エスケープされた文字をエスケープされていない状態で返すかどうかの指定。