4

私は scribble を使用するのは初めてですが、scribble 言語を使用するのではなく、自分のプログラムでその構文を使用する方法がわかりません。

> (define ht (make-hash '(("Name" . "Simon"))))
> (define template "Hello @Name")
> (function-i-dont-know ht template)
"Hello Simon"

私が探している機能は何ですか?存在するはずですが、ドキュメントで見つけることができません。

4

3 に答える 3

4

at-exp選択した言語で @ 式を使用するように追加します。

#lang at-exp racket

(define x (random 5))
(define y (random 5))

@~a{@x + @y = @(+ x y)}

出力: 「3 + 1 = 4」

于 2015-05-13T07:24:26.220 に答える
3

@soegaard が提供した答えは本当に十分に完全ですが、より一般的なテンプレート システムを探している人のために、これを行う 1 つの方法を示します。

重要なことは、@ フォームは Racket コードを記述する別の方法であることを覚えておくことです。そのため、特定のハッシュ テーブルに基づいて名前を置き換える一般的な方法を実際に探しています。(Racket にはそれを行う方法がたくさんあるので、@ フォームを使用してそれを行う方法はたくさんあります。)

Lこれは、パラメーターに保持されているハッシュ テーブルの値を検索するルックアップ関数を使用します。このパラメーターはテキストをレンダリングするときのみ「ライブ」であるため、実際にはサンクを生成して、テキストがレンダリングされるまでルックアップを遅らせます。(より便利なキーのシンボルを保持するために、ハッシュ テーブルを少し変更しました。)output関数 from を使用scribble/textして、テンプレート内の多くの種類の値 (入れ子になったリストなど) を許可する結果を生成します。同じ理由で、結果に文字列を試して使用する必要はありません。これは単なるリストです。次に、with-output-to-stringを使用してテキストを文字列に収集します。

#lang at-exp racket
(require scribble/text)

(define current-replacements (make-parameter #f))
(define (L key) (λ() (hash-ref (current-replacements) key)))
(define (render-with-hash ht template)
  (parameterize ([current-replacements ht])
    (with-output-to-string (λ() (output template)))))

(define ht (make-hash '([Name . "Simon"])))
(define template @list{Hello @L['Name]})
(render-with-hash ht template) ; => "Hello Simon"

もう少し便利なバリエーションはL、引用を冗長にするマクロを使用することです。

...
(define-syntax-rule (L key) (λ() (hash-ref (current-replacements) 'key)))
...
(define template @list{Hello @L[Name]})
...

...または、{}s は文字列の @ 構文にすぎないため、ハッシュ キーに文字列を使用する方法に戻ります。

#lang at-exp racket
(require scribble/text)

(define current-replacements (make-parameter #f))
(define (L key) (λ() (hash-ref (current-replacements) key)))
(define (render-with-hash ht template)
  (parameterize ([current-replacements ht])
    (with-output-to-string (λ() (output template)))))

(define ht (make-hash '(["Name" . "Simon"])))
(define template @list{Hello @L{Name}})
(render-with-hash ht template) ; => "Hello Simon"

ここで留意すべき 1 つの注意点は{}、たとえば、テキスト コンテンツに改行がある場合、s はいくつかの文字列になる可能性があるということです。それに対処したい場合は、L関数を調整して複数の引数を受け入れ、それらを一緒に追加し、ルックアップが完了する前にスペースを正規化できます。

#lang at-exp racket
(require scribble/text)

(define current-replacements (make-parameter #f))
(define (L . keys)
  (λ() (hash-ref (current-replacements)
                 (regexp-replace #px"\\s+" (string-append* keys) " "))))
(define (render-with-hash ht template)
  (parameterize ([current-replacements ht])
    (with-output-to-string (λ() (output template)))))

(define ht (make-hash '(["First Name" . "Simon"])))
(define template @list{Hello @L{First
                       Name}})
(render-with-hash ht template) ; => "Hello Simon"

これらすべてで少し厄介なのは、ハッシュ テーブルを保持するパラメーターの使用です。このようなものは、使用するキーが事前にわからない場合にのみ必要です。ほとんどの場合、そうします。そのためには、単純な関数になるテンプレートへの引数として単純な変数を使用できます。

#lang at-exp racket
(require scribble/text)

(define (template Name)
  @list{Hello @Name})
(with-output-to-string (λ() (output (template "Simon"))))
; => "Hello Simon"

最後にもう 1 つ注意してください。outputこれらのすべてで使用したので、テキスト内にネストされた構造を持つことができます。必要なのは一連の文字列だけである場合は、次を使用できますstring-append

#lang at-exp racket
(define (template Name)
  @string-append{Hello @Name})
(template "Simon") ; => "Hello Simon"

または、@soegaardの答えのように、関数を使用します。これは、一連の文字列値を追加できる(および文字列以外の値をingする)ことができる(文字列への)~a安価なバージョンのようなものです。outputdisplay

#lang at-exp racket
(define (template Name)
  @~a{Hello @Name})
(template "Simon") ; => "Hello Simon"
于 2015-05-15T02:31:50.130 に答える
1

まず、Scribble は Racket コードのフロントエンドにすぎないことを理解してください。Scribble が行うことは、入力と出力の実行可能な Racket コードを取得することだけです。

これは、template文字列で Scribble リーダーを使用すると、次のようになることを意味します。

"Hello" Name

それを単純なRacketコードと想像してみてください。これは、文字列リテラルの"Hello"後に という変数への参照が続くだけNameです。この結果は Racket コンパイラに渡され、実行可能なコードにコンパイルされます。

繰り返しますが、Scribble はテンプレート エンジンではなく、プログラミング言語です。Scribble はやみくもにコードを吐き出すだけなので、あなたが説明するような「置換」の概念はありません。あらゆる種類の文字列置換を実行するには、このコードを実行する必要があります。


モジュールを使用することで、上で説明したことを Racket で実際に行うことがracket/sandboxできます。これにより、自己完結型のサンドボックス化されたエバリュエーターを作成できます。

(require racket/sandbox
         scribble/reader)

(define (scribble-eval-string input-str environment)
  (define eval (make-evaluator 'racket))
  (define input (read-inside (open-input-string input-str)))
  (for ([(k v) (in-hash environment)])
    (eval `(define ,(string->symbol k) ,v)))
  (string-append*
   (for/list ([expr (in-list input)])
     (eval `(#%expression ,expr)))))

この関数は 4 つのことを行います。まず、racket言語のクリーンなエバリュエーターを作成します。次に、文字列入力モードで入力を読み取り、リストを生成するread-insidefromを使用して入力を読み取ります。scribble/reader入力では、生成される値は になります'("Hello " Name)

次に、変数をハッシュ テーブルからサンドボックスの環境に挿入する必要があります。これはdefine、ハッシュ テーブル内の各キーと値のペアの一連のフォームを手動で評価することによって行われます。最後に、入力リストの各要素を式として評価し、結果を 1 つの文字列に連結します。

これらすべてが整ったら、次のことができます。

(define environment (make-hash '(("Name" . "Simon"))))
(define input "Hello @Name")

> (scribble-eval-string input environment)
"Hello Simon"

これは良い考えですか?おそらくそうではありません。Scribble はプログラミング言語であるため、プログラム全体をオンザフライで効果的にコンパイルしてから実行します。データのいずれかがユーザーからのものである場合、プログラムに巨大なセキュリティ ホールが導入されています。

ダム文字列の置換だけが必要な場合は、formatまたは同様のものを使用してください。ただし、Scribble のすべての機能が本当に必要な場合は、次のようにして利用できるようにすることができます。

于 2015-05-13T07:22:28.823 に答える