在 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!
因此,直接在find 的结果上使用index? 是不安全,除非您知道搜索不会失败。如果无论如何都需要提取索引信息,安全的做法是先测试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
这些只是实现它的安全方法的示例,具体取决于您的需要。请注意,none 在if 或either 中充当条件测试的false,因此在这种情况下使用found? 是多余的。
现在让我们来解释一下给您带来困惑的核心问题。
Rebol 语言有一个称为series 的基本概念,string! 数据类型从该概念派生而来。理解和正确使用系列是能够以惯用方式使用 Rebol 语言的关键部分。系列在其他语言中看起来像通常的列表和类似字符串的数据类型,但它们不相同。一个系列由:
- 值列表(对于字符串,它是字符列表)
- 隐式索引(为简单起见,我们可以称其为游标)
以下描述将仅关注字符串,但相同的规则适用于所有系列数据类型。我将在下面的示例中使用index? 函数来将隐式索引显示为整数。
默认情况下,当你创建一个新字符串时,光标在head位置:
>> s: "hello"
>> head? s
== true
>> index? s
== 1
但是可以移动光标指向字符串中的其他地方:
>> next s
== "ello"
>> skip s 3
== "lo"
>> length? skip s 3
== 2
如您所见,带有移动光标的字符串不仅从光标位置显示,而且所有其他字符串(或系列)函数都会考虑该位置。 p>
此外,您还可以设置每个指向字符串的引用的光标:
>> 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]
如您所见,您可以根据需要对给定字符串(或系列)有尽可能多的不同引用,每个引用都有自己的 cursor 值,但都指向相同的 基础值列表。
序列属性的一个重要结果:您不需要像在其他语言中那样依赖整数索引来操作字符串(和其他序列),您可以简单地利用出现的光标使用任何系列参考来执行您需要的任何计算,您的代码将简短、干净且非常易读。尽管如此,整数索引有时在系列中还是很有用的,但您很少需要它们。
现在让我们回到您在字符串中搜索的用例。
>> 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 语言中的序列而不是单纯的整数索引是多么简单和高效。
现在,这是我对您的问题的看法:
不需要魔法,只要充分利用series和find函数,如上图。
Red 不会改变这一点。系列是 Rebol 语言简单而强大的基石。
change 应该是最快的方法,但是,如果您有许多替换要对长字符串进行操作,则重建一个新字符串而不是更改原始字符串通常会带来更好的性能,因为它可以避免当替换字符串与它们替换的部分大小不同时移动内存块。