Racket 什么';在哈希表中使用环境呈现scribble字符串的函数是什么?

Racket 什么';在哈希表中使用环境呈现scribble字符串的函数是什么?,racket,scribble,Racket,Scribble,我不熟悉使用scribble,但我不知道如何在自己的程序中使用它的语法,而不是使用scribble语言 > (define ht (make-hash '(("Name" . "Simon")))) > (define template "Hello @Name") > (function-i-dont-know ht template) "Hello Simon" 我要找的函数是什么?它必须存在,但我在文档中找不到它。首先,请理解Scribble只不过是Racket代码的前

我不熟悉使用scribble,但我不知道如何在自己的程序中使用它的语法,而不是使用scribble语言

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

我要找的函数是什么?它必须存在,但我在文档中找不到它。

首先,请理解Scribble只不过是Racket代码的前端。Scribble所做的只是获取一些输入和输出可执行的Racket代码

这意味着在
模板
字符串上使用Scribble reader将为您提供以下信息:

"Hello" Name
把它想象成普通的敲诈代码。它只不过是字符串literal
“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
语言创建了一个干净的计算器。接下来,它使用
scribble/reader
中的
read inside
读取输入,这将以字符串输入模式读取输入并生成一个列表。输入时,生成的值将是
”(“Hello”名称)

接下来,它需要将散列表中的变量注入沙箱环境。这是通过为哈希表中的每个键/值对手动计算一组
define
表单来完成的。最后,它将输入列表的每个元素作为表达式求值,然后将结果连接到单个字符串中

所有这些就绪后,您可以执行以下操作:

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

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


这是个好主意吗?可能不会。因为Scribble是一种编程语言,所以您实际上是在动态编译整个程序,然后执行它。如果任何数据来自某个用户,那么您的程序就存在一个巨大的安全漏洞


如果您只需要替换哑字符串,只需使用
格式
或类似的方法即可。然而,如果你真的需要Scribble的全部功能,你可以这样做,让它对你有用。

添加
at exp
,在你选择的语言中使用@-表达式

#lang at-exp racket

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

@~a{@x + @y = @(+ x y)}
输出:
“3+1=4”

@soegaard给出的答案确实足够完整,但对于 为了那些只会寻找更普通的模板的人 系统,这里有一种方法

最重要的是要记住,"形式"只是另一种表达方式 写拍子代码,所以我们真的在寻找一种 根据给定的哈希表替换名称。(因为球拍有成吨的重量 要做到这一点,有很多方法可以通过"表单"做到这一点

这个函数使用查找函数
L
,在哈希表中查找值 它被保存在一个计量器里。因为这个参数只有在 渲染文本时,它实际上会生成thunk以延迟查找 直到文本被呈现。(我稍微修改了哈希表以保持不变 它使用来自的
输出
功能
scribble/text
生成允许输入多种值的结果 模板(如嵌套列表)。出于同样的原因,没有必要 要尝试使用字符串作为结果,它只是一个列表。 然后,使用输出为字符串的
将文本收集到字符串中

#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"
这里需要注意的一点是,
{}
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"
最后一个旁注:我在所有这些东西中使用了
output
,因此您可以 在文本中有嵌套的事物结构。如果你只需要一个 一组字符串,您可以使用
string append

#lang at-exp racket
(define (template Name)
  @string-append{Hello @Name})
(template "Simon") ; => "Hello Simon"
或者,正如@soegaard的回答一样,使用
~a
函数,这是一种 廉价版本的
输出
(放入字符串),可以附加一组 字符串值(和
显示
非字符串值):


我不清楚你到底想做什么。您希望使用Scribble的at表达式读取器解析字符串,并且希望使用哈希表作为变量绑定的环境?是和是。虽然我可以使用一些不同于哈希表的东西作为环境,如果它更简单的话。谢谢你的回复。非常感谢你透彻而清晰的回答。“这是个好主意吗?可能不是。”我认为“at syntax”是所使用的模板引擎。不过你是对的。模板引擎是我正在寻找的。它只是吸引了我在模板中提供全部球拍。我正在编写自己的模板和数据,因此从这个角度来看,没有外部安全风险。@Alexis:这是一个非常糟糕的答案,有几个原因。首先,Scribble@-form语法不会像s表达式那样“生成”任何代码:它不是
#lang at-exp racket
(define (template Name)
  @~a{Hello @Name})
(template "Simon") ; => "Hello Simon"