Rebol中的'reword'功能是什么?我该如何使用它?

时间:2013-02-17 18:56:24

标签: templates template-engine rebol variable-expansion rebol3

我今天看到有人提到reword功能,但是文档非常简短。它看起来像shell脚本环境变量替换,或者可能是正则表达式替换,但不同。我如何使用此功能以及我将遇到什么样的问题?

1 个答案:

答案 0 :(得分:14)

这里有龙!

reword函数是一种尝试,以一种与我们的工作方式一致的方式向Rebol添加shell样式的字符串插值。与许多Rebol的系列函数不同,它实际上是针对字符串类型进行优化的,而设计则反映了这一点。当前版本是一个设计原型,最终可以作为原生版重做,但它确实按设计工作,因此讨论它是如何工作以及如何使用它是有意义的。

reword做什么?

基本上这个:

>> reword "$a is $b." [a "This" b "that"]
== "This is that."

它接受一个模板字符串,它搜索转义序列,并用相应的替换值替换它们。这些值也作为对象,映射或键和值块传递给函数。键可以是几乎任何东西,甚至是数字:

>> reword "$1 is $2." [1 "This" 2 "that"]
== "This is that."

如果密钥已经不是字符串,则将其转换为字符串。如果将它们转换为相同的字符串,那么键被认为是相同的,这就是当你做这样的事情时会发生的事情:

>> reword "A $a is $a." [a "fox" "a" "brown"]
== "A brown is brown."

它不像正则表达式替换那样,它是基于关键字的。如果您在值块中有多次指定的键,那么该键的最后一个值就是我们刚才看到的那个值。只是跳过任何未设置或无值的值,因为将这些值放入字符串时没有意义。

您也可以使用其他转义标志,即使是多字符转义标志:

>> reword/escape "A %%a is %%b." [a "fox" b "brown"] "%%"
== "A fox is brown."

甚至根本没有逃生标志,它将取代所有地方的钥匙:

>> reword/escape "I am answering you." [I "Brian" am "is" you "Adrian"] none
== "Brian is answerBrianng Adrian."

哎呀,这不起作用。这是因为密钥不区分大小写,并且它们不需要被空格或其他此类分隔符包围。但是,如果将它们指定为字符串,则可以在键中放置空格,因此效果更好:

>> reword/escape "I am answering you." ["I am" "Brian is" you "Adrian"] none
== "Brian is answering Adrian."

尽管如此,在没有转义字符的情况下执行reword模板往往会变得棘手而且速度稍慢,所以不会经常这样做。

虽然有一个更好的技巧......

功能替换

reword变得非常有趣时,当你使用函数作为替换值时,因为该函数在每次重写时都会被调用。说,你想用计数器代替:

>> reword "$x then $x and $x, also $x" object [y: 1 x: does [++ y]]
== "1 then 2 and 3, also 4"

或者甚至是位置,因为它可以将字符串位置作为参数:

>> reword "$x then $x and $x, also $x" object [x: func [s] [index? s]]
== "1 then 9 and 16, also 25"

等等,这看起来不正确,这些数字似乎已关闭。这是因为该函数返回模板字符串的索引,而不是结果字符串。在编写这些函数时要记住这一点很好。该功能甚至不必仅分配给一个密钥,它可以检测或使用它:

>> reword "$x or $y" object [x: y: func [s] [ajoin ["(it's " copy/part s 2 ")"]]]
== "(it's $x) or (it's $y)"

参见模板变量,转义和所有。并且该函数可能有副作用,如此行计数器:

>> reword/escape "Hello^/There^/nl" use [x] [x: 0 map reduce ["^/" does [++ x "^/"] "nl" does [x]]] ""
== "Hello^/There^/2"

它甚至带有/into选项,因此您可以使用它来分阶段构建字符串。

但是对于那些来自插入内置语言的人来说,最大的问题是......

为什么值阻止,为什么不使用像普通语言这样的变量?

因为 Rebol不能正常工作。 Rebol没有词法绑定,它会做其他事情,所以在一个字符串中,没有办法知道从哪里获取变量的值而不这么说。在其中一种具有插值的shell语言中,它等同于必须将对整个环境的引用传递给插值函数。但是,嘿,我们可以在Rebol中做到这一点:

>> use [x] [x: func [s] [index? s] reword "$x then $x and $x, also $x" bind? 'x]
== "1 then 9 and 16, also 25"

bind?方法将在use,绑定循环和函数中起作用。如果您在对象中,也可以使用self

>> o: object [x: func [s] [index? s] y: func [s] [reword s self]]
== make object! [
    x: make function! [[s][index? s]]
    y: make function! [[s][reword s self]]
]
>> o/y "$x then $x and $x, also $x"
== "1 then 9 and 16, also 25"

但要小心,否则你最终可能会做这样的事情:

>> o/y "$x then $x and $x, also $x, finally $y"
** Internal error: stack overflow

龙! 这是保持变量和替换键分开的一个很好的理由......