3

多くのデータインポートコードを書くためにパースレットを調べています。全体として、ライブラリは良さそうに見えますが、1 つ苦労しています。入力ファイルの多くは固定幅であり、実際のフィールドがそうでない場合でも、幅はフォーマット間で異なります。たとえば、9 文字の通貨を持つファイルと、11 文字 (またはその他) の別のファイルを取得する場合があります。パースレットアトムに固定幅の制約を定義する方法を知っている人はいますか?

理想的には、通貨を理解するアトムを定義できるようにしたいと考えています (オプションのドル記号、千単位の区切り記号などを使用)。そして、その場で、古いアトムに基づいて新しいアトムを作成できるようになります。これは、正確に N 文字を解析することを除いて、まったく同じです。

そのようなコンビネータはパースレットに存在しますか? そうでない場合、自分で書くことは可能/困難ですか?

4

3 に答える 3

1

パーサー クラスのメソッドは、基本的にはパーレット アトムのジェネレーターです。これらのメソッドの最も単純な形式は、呼び出されるたびに同じアトムを返す「ルール」メソッドです。単純な獣ではない独自のジェネレーターを作成するのも同様に簡単です。このトリックの説明については、 http://kschiess.github.com/parslet/tricks.htmlを参照してください(一致する文字列は大文字と小文字を区別しません)。

あなたの通貨パーサーはいくつかのパラメーターしかないパーサーであり、好みに合わせて調整された通貨パーサーを返すメソッド (def ... end) をおそらく作成できるように思えます。たぶん、初期化とコンストラクターの引数を使用することさえありますか? (つまり: MoneyParser.new(4,5))

さらにヘルプが必要な場合は、質問をメーリング リストに送信してください。このような質問は、コードで説明すると簡単に答えられることがよくあります。

于 2011-04-08T11:38:49.687 に答える
1

このようなものはどうですか...

class MyParser < Parslet::Parser
    def initialize(widths)
        @widths = widths
        super
    end

    rule(:currency)  {...}
    rule(:fixed_c)   {currency.fixed(@widths[:currency])}


    rule(:fixed_str) {str("bob").fixed(4)}
end 

puts MyParser.new.fixed_str.parse("bob").inspect

これは失敗します:

"Expected 'bob' to be 4 long at line 1 char 1"

方法は次のとおりです。

require 'parslet'

class Parslet::Atoms::FixedLength < Parslet::Atoms::Base  
  attr_reader :len, :parslet
  def initialize(parslet, len, tag=:length)
    super()

    raise ArgumentError, 
      "Asking for zero length of a parslet. (#{parslet.inspect} length #{len})" \
      if len == 0

    @parslet = parslet
    @len = len
    @tag = tag
    @error_msgs = {
      :lenrep  => "Expected #{parslet.inspect} to be #{len} long", 
      :unconsumed => "Extra input after last repetition"
    }
  end

  def try(source, context, consume_all)
    start_pos = source.pos

    success, value = parslet.apply(source, context, false)

    return succ(value) if success && value.str.length == @len

    context.err_at(
      self, 
      source, 
      @error_msgs[:lenrep], 
      start_pos, 
      [value]) 
  end

  precedence REPETITION
  def to_s_inner(prec)
    parslet.to_s(prec) + "{len:#{@len}}"
  end
end

module Parslet::Atoms::DSL
  def fixed(len)
    Parslet::Atoms::FixedLength.new(self, len)
  end
end
于 2014-02-12T05:34:46.657 に答える