在 Red/Rebol 中搜索字符串非常简单方便。关于你遇到的问题,让我为你详细解包:
首先,解释器会以错误消息的形式向您提供有关您做错了什么的良好提示:index? expected series argument of type: series port
. 这意味着您使用index?
了错误的数据类型。那是怎么发生的?仅仅因为find
函数返回一个none
值以防搜索失败:
>> str: "abcdefghijklmopqrz"
>> find str "o"
== "pqrz"
>> type? find str "o"
== string!
>> find str "n"
== none
>> type? find str "n"
== none!
所以,index?
直接在结果上使用find
是不安全的,除非你知道搜索不会失败。如果无论如何都需要提取索引信息,安全的方法是先测试结果find
:
>> all [pos: find str "o" index? pos]
== 14
>> all [pos: find str "n" index? pos]
== none
>> if pos: find str "o" [print index? pos]
== 14
>> print either pos: find str "n" [index? pos][-1]
== -1
这些只是实现它的安全方法的示例,具体取决于您的需要。请注意,在or中none
充当false
条件测试,因此在这种情况下使用是多余的。if
either
found?
现在让我们对给您带来困惑的核心问题进行一些说明。
Rebol 语言有一个称为 a 的基本概念,数据类型series
从该概念string!
派生而来。理解和正确使用系列是能够以惯用方式使用 Rebol 语言的关键部分。系列在其他语言中看起来像通常的列表和类似字符串的数据类型,但它们并不相同。一个系列由:
- 值列表(对于字符串,它是字符列表)
- 隐式索引(为简单起见,我们可以称其为游标)
以下描述将仅关注字符串,但相同的规则适用于所有系列数据类型。我将index?
在下面的示例中使用函数来将隐式索引显示为整数。
默认情况下,当您创建一个新字符串时,光标位于头部位置:
>> s: "hello"
>> head? s
== true
>> index? s
== 1
但是可以移动光标以指向字符串中的其他位置:
>> next s
== "ello"
>> skip s 3
== "lo"
>> length? skip s 3
== 2
如您所见,带有移动光标的字符串不仅从光标位置显示,而且所有其他字符串(或系列)函数都会考虑该位置。
此外,您还可以为每个指向字符串的引用设置光标:
>> a: next s
== "ello"
>> b: skip s 3
== "lo"
>> s: at s 5
== "o"
>> reduce [a b s]
== ["ello" "lo" "o"]
>> reduce [index? a index? b index? s]
== [2 4 5]
正如您所看到的,您可以根据需要对给定字符串(或系列)有尽可能多的不同引用,每个引用都有自己的光标值,但都指向相同的基础值列表。
系列属性的一个重要结果:您不需要像在其他语言中那样依赖整数索引来操作字符串(和其他系列),您可以简单地利用任何系列引用附带的光标来执行您需要的任何计算,并且您的代码将简短、干净且非常易读。尽管如此,整数索引有时在系列中可能很有用,但您很少需要它们。
现在让我们回到您在字符串中搜索的用例。
>> STR: "abcdefghijklmopqrz"
>> find STR "z"
== "z"
>> find STR "n"
== none
这就是您所需要的,您不必提取索引位置即可将结果值用于您需要执行的几乎所有计算。
>> pos: find STR "o"
>> if pos [print "found"]
found
>> print ["sub-string from `o`:" pos]
sub-string from `o`: opqrz
>> length? pos
== 5
>> index? pos
== 14
>> back pos
== "mopqrz"
>> skip pos 4
== "z"
>> pos: find STR "n"
>> print either pos ["found"]["not found"]
not found
>> print either pos [index? pos][-1]
-1
这是一个简单的示例,展示如何在不显式使用整数索引的情况下进行子字符串提取:
>> s: "The score is 1:2 after 5 minutes"
>> if pos: find/tail s "score is " [print copy/part pos find pos " "]
1:2
稍加练习(控制台非常适合此类实验),您将看到完全依赖 Rebol 语言中的系列而不是单纯的整数索引是多么简单和高效。
现在,这是我对您的问题的看法:
不需要魔法,只要find
充分利用系列和功能,如上图。
红色不会改变这一点。系列是使 Rebol 语言简单而强大的基石。
change
应该是最快的方法,但是,如果您有许多替换要对长字符串进行操作,则重建一个新字符串而不是更改原始字符串,通常会带来更好的性能,因为它可以避免在没有替换字符串时移动内存块与他们更换的零件尺寸相同。