http://kschiess.github.io/parslet/parser.htmlから
入力のキャプチャ
場合によっては、パーサーは、既に照合されたものと照合する必要があります。たとえば、Ruby のヒアドキュメントについて考えてみましょう。
str = <-HERE
This is part of the heredoc.
HERE
この種のドキュメントを照合するための鍵は、最初に入力の一部をキャプチャし、次にキャプチャした部分に基づいて残りのパーサーを構築することです。これは、最も単純な形式では次のようになります。
match['ab'].capture(:capt) >> # create the capture
dynamic { |s,c| str(c.captures[:capt]) } # and match using the capture
ここで重要なのは、dynamic
ブロックが遅延パーサーを返すことです。使用されている時点でのみ評価され、実行時に現在のコンテキストが渡されて参照されます。
-- 更新: 実例を追加するには --
あなたの例では:
require 'parslet'
require 'parslet/convenience'
class Mini < Parslet::Parser
rule(:name) { match("[a-zA-Z]") >> match('\\w').repeat }
rule(:text_within_the_block) {
str('Marker ') >>
name.capture(:namez).as(:name) >>
str(" ") >>
dynamic { |_,scope|
(str(scope.captures[:namez]).absent? >> any).repeat
}.as(:text_block) >>
dynamic { |src,scope| str(scope.captures[:namez]) }
}
root (:text_within_the_block)
end
puts Mini.new.parse_with_debug("Marker BOB some text BOB") .inspect
#=> {:name=>"BOB"@7, :text_block=>"some text "@11}
これにはいくつかの変更が必要でした。
- rule(:name) を単一の単語に一致するように変更
str(" ")
し、その単語が終了したことを検出する a を追加しました。(注: \w は [A-Za-z0-9_] の略なので、数字が含まれます)
- 「任意」の一致を、テキストではないテキストを条件とするように変更しました
:name
。(それ以外の場合は、'BOB' を消費し、一致に失敗します。つまり、貪欲です!)