1

\1典型的な正規表現の機能と同様に、parslet の前の文字列を後方参照する方法はありますか?

次のようなブロック内の文字を抽出したい:

Marker SomeName
 some random text, numbers123
 and symbols !#%
SomeName  

「Marker」は既知の文字列ですが、「SomeName」は事前に知られていないため、次のようなものが必要だと思います。

rule(:name) { ( match('\w') >> match('\w\d') ).repeat(1) } 
rule(:text_within_the_block) {
 str('Marker') >>  name >> any.repeat.as(:text_block) >> backreference_to_name 
}  

私が知らないのは、Parslet や Ruby 言語を使用して backreference_to_name ルールを記述する方法です。

4

2 に答える 2

3

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' を消費し、一致に失敗します。つまり、貪欲です!)
于 2014-02-11T02:26:41.123 に答える