Adr*_*ian 9 templates template-engine rebol variable-expansion rebol3
我reword今天看到有人提到这个功能,但是它的文档非常简短.它看起来像shell脚本环境变量替换,或者可能是正则表达式替换,但不同.我如何使用此功能以及我将遇到什么样的陷阱?
Bri*_*anH 14
该reword函数是一个实验,以一种与我们的工作方式一致的方式向Rebol添加shell样式的字符串插值.与许多Rebol的系列函数不同,它确实针对仅仅处理字符串类型进行了优化,而设计反映了这一点.当前版本是一个设计原型,最终将作为原生版重做,但它确实按设计工作,因此讨论它是如何工作以及如何使用它是有意义的.
reword办?基本上这个:
>> reword "$a is $b." [a "This" b "that"]
== "This is that."
Run Code Online (Sandbox Code Playgroud)
它接受一个模板字符串,它搜索转义序列,并用相应的替换值替换它们.这些值也作为对象,映射或键和值块传递给函数.键可以是几乎任何东西,甚至是数字:
>> reword "$1 is $2." [1 "This" 2 "that"]
== "This is that."
Run Code Online (Sandbox Code Playgroud)
如果密钥已经不是字符串,则将其转换为字符串.如果将它们转换为相同的字符串,则认为键是相同的,这是当您执行以下操作时发生的情况:
>> reword "A $a is $a." [a "fox" "a" "brown"]
== "A brown is brown."
Run Code Online (Sandbox Code Playgroud)
它不像正则表达式替换那样,它是基于关键字的.如果您在值块中有多次指定的键,那么该键的最后一个值就是我们刚才看到的那个值.只是跳过任何未设置或无值的值,因为将这些值放入字符串时没有任何意义.
您也可以使用其他转义标志,即使是多字符转义标志:
>> reword/escape "A %%a is %%b." [a "fox" b "brown"] "%%"
== "A fox is brown."
Run Code Online (Sandbox Code Playgroud)
甚至根本没有逃生标志,它将取代所有地方的钥匙:
>> reword/escape "I am answering you." [I "Brian" am "is" you "Adrian"] none
== "Brian is answerBrianng Adrian."
Run Code Online (Sandbox Code Playgroud)
哎呀,那没用.这是因为密钥不区分大小写,并且它们不需要被空格或其他此类分隔符包围.但是,如果将它们指定为字符串,则可以在键中放置空格,因此这样做效果更好:
>> reword/escape "I am answering you." ["I am" "Brian is" you "Adrian"] none
== "Brian is answering Adrian."
Run Code Online (Sandbox Code Playgroud)
尽管如此,在reword没有转义字符的情况下制作模板往往会变得棘手而且速度稍慢,所以它并不常用.
虽然有一个更好的技巧......
凡reword变得非常有趣的是,当你使用一个函数作为一个替代值,因为该功能被称为与每一个措词.说,你想用一个柜台替换:
>> reword "$x then $x and $x, also $x" object [y: 1 x: does [++ y]]
== "1 then 2 and 3, also 4"
Run Code Online (Sandbox Code Playgroud)
或者甚至是位置,因为它可以将字符串位置作为参数:
>> reword "$x then $x and $x, also $x" object [x: func [s] [index? s]]
== "1 then 9 and 16, also 25"
Run Code Online (Sandbox Code Playgroud)
等等,看起来不对,这些数字似乎没有了.那是因为函数返回模板字符串的索引,而不是结果字符串.在编写这些函数时要记住这一点很好.该功能甚至不必分配给一个密钥,它可以检测或使用它:
>> reword "$x or $y" object [x: y: func [s] [ajoin ["(it's " copy/part s 2 ")"]]]
== "(it's $x) or (it's $y)"
Run Code Online (Sandbox Code Playgroud)
请参阅模板变量,转义和所有.并且该函数可能有副作用,如此行计数器:
>> reword/escape "Hello^/There^/nl" use [x] [x: 0 map reduce ["^/" does [++ x "^/"] "nl" does [x]]] ""
== "Hello^/There^/2"
Run Code Online (Sandbox Code Playgroud)
它甚至带有/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"
Run Code Online (Sandbox Code Playgroud)
该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"
Run Code Online (Sandbox Code Playgroud)
但要小心,否则你最终可能会做这样的事情:
>> o/y "$x then $x and $x, also $x, finally $y"
** Internal error: stack overflow
Run Code Online (Sandbox Code Playgroud)
龙!这是保持变量和替换键分开的一个很好的理由......