9

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

4

1 回答 1

14

这里有龙!

reword函数是一个实验,以一种适合我们做事方式的方式将 shell 样式的字符串插值添加到 Rebol。与 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."

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

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

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

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

于 2013-02-18T01:31:18.713 回答