在散列 table 中使用环境渲染涂鸦字符串的功能是什么?
What's the function to render scribble string with the environment in a hash table?
我刚开始使用 scribble,但我不知道如何在我自己的程序中使用它的语法,而不是使用 scribble 语言。
> (define ht (make-hash '(("Name" . "Simon"))))
> (define template "Hello @Name")
> (function-i-dont-know ht template)
"Hello Simon"
我正在寻找的功能是什么?肯定是有的,但是我在文档里找不到。
首先要明白,Scribble 只不过是 Racket 代码的前端。 Scribble 所做的只是获取一些输入和输出 executable Racket code.
这意味着在您的 template
字符串上使用 Scribble reader 只会给您:
"Hello" Name
把它想象成普通的 Racket 代码。它只不过是字符串文字 "Hello"
后跟对名为 Name
的变量的引用。然后将此结果传递给 Racket 编译器并 编译 为 executable 代码。
所以,Scribble 不是模板引擎,它是一种编程语言。没有你描述的 "substitution" 的概念,因为 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)
.
接下来,它需要将散列 table 中的变量注入到沙箱的环境中。这是通过为散列 table 中的每个 key/value 对手动评估一组 define
形式来完成的。最后,它将输入列表的每个元素计算为一个表达式,然后将结果连接成一个字符串。
准备好所有这些后,您可以执行以下操作:
(define environment (make-hash '(("Name" . "Simon"))))
(define input "Hello @Name")
> (scribble-eval-string input environment)
"Hello Simon"
这是个好主意吗?可能不会。由于 Scribble 是一种编程语言,您可以有效地即时编译整个程序,然后执行它。如果任何数据来自用户,那么您就在程序中引入了巨大的安全漏洞。
如果您只需要替换哑字符串,只需使用 format
或类似的东西。但是,如果您真的需要 Scribble 的全部功能,您可以执行类似的操作以使其可用。
添加 at-exp
以在您选择的语言中使用 @ 表达式。
#lang at-exp racket
(define x (random 5))
(define y (random 5))
@~a{@x + @y = @(+ x y)}
输出:
“3 + 1 = 4”
@soegaard 的回答确实够完整,但是对于
为了那些只会寻找更常见模板的人
系统,这是一种方法。
最主要的是要记住 @-forms 只是另一种方式
编写 Racket 代码,所以我们真的在寻找一种通用的方法
根据给定的哈希值替换名称-table。 (因为 Racket 有很多
有很多方法可以做到这一点,使用@-forms 有很多方法可以做到这一点。)
这个使用查找函数 L
查找散列中的值 table
保存在参数中。由于此参数仅当 "live"
呈现文本时,它实际上会产生 thunk 以延迟查找
直到文本被渲染。 (我稍微修改了散列 table 以保存
用于更方便的键的符号。)它使用 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]})
...
... 或者,因为 {}
s 只是字符串的 @-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"
所有这些中有点尴尬的是使用
参数持有一个散列 table。只有当
您不知道预先使用的密钥。在大多数情况下,你这样做,
为此,您可以只使用普通变量作为参数
变成简单函数的模板:
#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
ing 非字符串值):
#lang at-exp racket
(define (template Name)
@~a{Hello @Name})
(template "Simon") ; => "Hello Simon"
我刚开始使用 scribble,但我不知道如何在我自己的程序中使用它的语法,而不是使用 scribble 语言。
> (define ht (make-hash '(("Name" . "Simon"))))
> (define template "Hello @Name")
> (function-i-dont-know ht template)
"Hello Simon"
我正在寻找的功能是什么?肯定是有的,但是我在文档里找不到。
首先要明白,Scribble 只不过是 Racket 代码的前端。 Scribble 所做的只是获取一些输入和输出 executable Racket code.
这意味着在您的 template
字符串上使用 Scribble reader 只会给您:
"Hello" Name
把它想象成普通的 Racket 代码。它只不过是字符串文字 "Hello"
后跟对名为 Name
的变量的引用。然后将此结果传递给 Racket 编译器并 编译 为 executable 代码。
所以,Scribble 不是模板引擎,它是一种编程语言。没有你描述的 "substitution" 的概念,因为 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)
.
接下来,它需要将散列 table 中的变量注入到沙箱的环境中。这是通过为散列 table 中的每个 key/value 对手动评估一组 define
形式来完成的。最后,它将输入列表的每个元素计算为一个表达式,然后将结果连接成一个字符串。
准备好所有这些后,您可以执行以下操作:
(define environment (make-hash '(("Name" . "Simon"))))
(define input "Hello @Name")
> (scribble-eval-string input environment)
"Hello Simon"
这是个好主意吗?可能不会。由于 Scribble 是一种编程语言,您可以有效地即时编译整个程序,然后执行它。如果任何数据来自用户,那么您就在程序中引入了巨大的安全漏洞。
如果您只需要替换哑字符串,只需使用 format
或类似的东西。但是,如果您真的需要 Scribble 的全部功能,您可以执行类似的操作以使其可用。
添加 at-exp
以在您选择的语言中使用 @ 表达式。
#lang at-exp racket
(define x (random 5))
(define y (random 5))
@~a{@x + @y = @(+ x y)}
输出: “3 + 1 = 4”
@soegaard 的回答确实够完整,但是对于 为了那些只会寻找更常见模板的人 系统,这是一种方法。
最主要的是要记住 @-forms 只是另一种方式 编写 Racket 代码,所以我们真的在寻找一种通用的方法 根据给定的哈希值替换名称-table。 (因为 Racket 有很多 有很多方法可以做到这一点,使用@-forms 有很多方法可以做到这一点。)
这个使用查找函数 L
查找散列中的值 table
保存在参数中。由于此参数仅当 "live"
呈现文本时,它实际上会产生 thunk 以延迟查找
直到文本被渲染。 (我稍微修改了散列 table 以保存
用于更方便的键的符号。)它使用 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]})
...
... 或者,因为 {}
s 只是字符串的 @-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"
所有这些中有点尴尬的是使用 参数持有一个散列 table。只有当 您不知道预先使用的密钥。在大多数情况下,你这样做, 为此,您可以只使用普通变量作为参数 变成简单函数的模板:
#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
ing 非字符串值):
#lang at-exp racket
(define (template Name)
@~a{Hello @Name})
(template "Simon") ; => "Hello Simon"