Искать строки в 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
Это были лишь примеры безопасных способов достижения этой цели в зависимости от ваших потребностей. Обратите внимание, что none
действует как false
для условных тестов в if
или either
, поэтому использование 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
Как видите, строка с перемещенным курсором не только отображается с позиции курсора, но также все другие строковые (или серии) функции будут учитывать эту позицию.
Кроме того, вы также можете установить курсор для каждой ссылки, указывающей на строку:
>> 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, чем на простые целочисленные индексы.
А теперь я отвечу на ваши вопросы:
Никакого волшебства не требуется, просто используйте серию и find
функцию адекватно, как показано выше.
Красный не собирается этого менять. Серии - это краеугольный камень того, что делает языки Rebol простыми и мощными.
change
должен быть самым быстрым способом, однако, если у вас есть много замен для работы с длинной строкой, восстановление новой строки вместо изменения исходной часто приводит к повышению производительности, так как это позволит избежать перемещения фрагментов памяти при замене строк. не того же размера, что и деталь, которую они заменяют.
person
DocKimbel
schedule
14.12.2015