在散列表中使用环境渲染scribble字符串的功能是什么?

时间:2015-05-13 06:56:46

标签: racket scribble

我是使用scribble的新手,但我无法弄清楚如何在我自己的程序中使用它的语法,而不是使用涂鸦语言。

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

我正在寻找什么功能?它必须存在,但我在文档中找不到它。

3 个答案:

答案 0 :(得分:4)

添加at-exp以您选择的语言使用@ -expressions。

#lang at-exp racket

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

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

输出:     " 3 + 1 = 4"

答案 1 :(得分:2)

@soegaard给出的答案非常完整,但对于 那些寻找更常见模板的人的缘故 系统,这是一种方法。

最重要的是要记住@ -forms只是另一种方式 编写球拍代码,所以我们真的在寻找一种通用的方法 基于给定的哈希表替换名称。 (因为球拍有很多 如何做到这一点,@ -forms有很多方法可以做到这一点。)

这个使用查找函数L来查找哈希表中的值 保存在一个paremeter中。由于此参数仅在“活动”时才有效 渲染文本,它实际上产生thunk以延迟查找 直到文本呈现。 (我稍微修改了哈希表以保持 用于更方便键的符号。)它使用来自output的函数 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]})
...

...或者,因为{}只是字符串的@ -syntax,所以请回到使用 散列键的字符串:

#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函数以接受多个 参数并将它们附加在一起,然后将空格标准化 查询已完成:

#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"

有一点在所有这些方面有点尴尬是使用a 参数持有哈希表。只有这样才需要这样的东西 你不知道提前使用的密钥。在大多数情况下你这样做, 为此你可以使用普通变量作为参数 成为简单函数的模板:

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

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

最后一点注意事项:我在所有这些事情中使用了output,所以你可以 在文本中嵌套了事物的结构。如果您只需要一个 一堆字符串,你可以使用string-append

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

或者,就像在@ soegaard的回答中一样,使用~a函数,这是一种 廉价版本的output(成一个字符串)可以附加一堆 字符串值(和display非字符串值):

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

答案 2 :(得分:1)

首先,要了解Scribble只不过是Racket代码的前端。 Scribble所做的只是输入和输出可执行的球拍代码

这意味着在template字符串上使用Scribble阅读器只会给你:

"Hello" Name

想象一下,作为普通的Racket代码。它只不过是字符串文字"Hello",后跟对名为Name的变量的引用。然后将此结果传递给Racket编译器并将编译传递给可执行代码。

再次, Scribble不是模板引擎,它是一种编程语言。没有像你描述的那样“替换”的概念,因为Scribble只是盲目地吐出代码。您需要运行此代码才能执行任何类型的字符串替换。

您可以使用racket/sandbox模块实际执行上面在Racket中所描述的内容,该模块允许您创建自包含的沙盒评估程序。

(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)))))

这个功能做了四件事。首先,它为racket语言创建了一个干净的评估程序。接下来,它使用read-inside中的scribble/reader读取输入,'("Hello " Name)以字符串输入模式读取输入并生成列表。在您的输入中,生成的值将为define

接下来,它需要将哈希表中的变量注入沙箱的环境中。这是通过手动为哈希表中的每个键/值对评估一组(define environment (make-hash '(("Name" . "Simon")))) (define input "Hello @Name") > (scribble-eval-string input environment) "Hello Simon" 表单来完成的。最后,它将输入列表的每个元素作为表达式进行计算,然后将结果连接成一个字符串。

完成所有这些后,您可以这样做:

format

这是个好主意吗?可能不是。由于Scribble是一种编程语言,因此您可以有效地编译整个程序,然后执行它。如果任何数据来自用户,那么您在程序中引入了一个巨大的安全漏洞。

如果你只需要替换哑字符串,只需使用allRecipt或类似的东西。但是,如果你真的需要Scribble的全部功能,你可以做这样的事情让你可以使用它。