Глава 5 - Скрипты
REBOL/Core Руководство пользователя Основное содержание Отправьте нам отзыв
Содержание:
1. Основные концепции
1.1 Переход к серии
1.2 Переход по порядку
1.3 Извлечение значений
1.4 Извлечение подсерии
1.5 Вставка и добавление
1.6 Удаление значений
1.7 Изменение значений
2. Серийные функции
2.1 Функции создания
2.2 Функции навигации
2.3 Информационные функции
2.4 Функции извлечения
2.5 Функции изменения
2.6 Функции поиска
2.7 Функции упорядочивания
2.8 Функции набора данных (группы)
3. Типы данных серий
3.1 Типы блоков
3.2 Типы строк
3.3 Псевдотипы
3.4 Функции проверки типов
4. Информация о серии
4.1 Length? (Длинна)
4.2 Head? (Голова)
4.3 Tail? (Хвост)
4.4 Index? (Индекс)
4.5 Offset? (Смещение)
5. Создание и копирование серии
5.1 Частичные Копии
5.2 Глубинные Копии
5.3 Исходные Копии
6. Серия Итерационные
6.1 Цикл Foreach
6.2 Цикл While
6.3 Цикл Forall
6.4 Цикл Forskip
6.5 Функция Break
7. Поиск в серии
7.1 Простой поиск
7.2 Доработка резюме
7.3 Частичные поиск
7.4 Позиция хвоста
7.5 Обратный поиск
7.6 Повторный поиск
7.7 Сопоставление
7.8 Поиск по шаблону
7.9 Выбор
7.10 Поиск и Замена
8. Сортировка серий
8.1 Простая сортировка
8.2 Групповая сортировка
8.3 Функции сравнения
9. Серия как набор данных
9.1 Unique (Уникальные)
9.2 Intersect (Пересечение)
9.3 Union (Объединение)
9.4 Exclude (Исключение)
9.5 Difference (Разница)
9.6 Exclude (Исключение)
10. Переменные нескольких серий
11. Уточнения модификации
11.1 Part (Часть)
11.2 Only (Только)
11.3 Dup (Дублирование)
1. Основные концепции
Концепция серии проста, и это фундаментальная концепция, которая используется везде и почти для всего в REBOL. Чтобы понять REBOL, вы должны понимать, как создавать и управлять сериями.
Серии представляет собой набор значений , расположенных в определённом порядке.
Например, это все серии:
1 2 3 4
A B C D
"ABCD"
10:30 4:20 7:11
В REBOL есть много типов серий. Блок, строка, список, URL-адрес, путь, электронная почта, файл, тег, двоичный файл, битовый набор, порт, хэш и изображение - все это серии, к которым можно получить доступ и обрабатывать одинаковым образом с использованием небольшого набором последовательных функций.
1.1 Переход по серии
Поскольку ряд представляет собой упорядоченный набор значений, вы можете перемещаться по нему из одной позиции в другую. В качестве примера возьмём серию из трёх цветов, определённых следующим блоком:
colors: [red green blue]
В этом блоке нет ничего особенного. Это серия из трёх слов. У него есть набор значений: red (красный), green (зелёный) и blue (синий). Значения организованы в определённом порядке: красный - первый, зелёный - второй, синий - третий..
Первая позиция блока называется head (голова). Эту позицию занимает слово красный. Последняя позиция блока называется tail (хвост). Это позиция сразу после последнего слова в блоке. Если бы вы нарисовали схему блока, это выглядело бы так:

Обратите внимание, что хвост находится за концом блока. Вскоре важность этого станет более ясной.
Переменная colors используются для обозначения блока. В настоящее время он установлен в заголовок блока:

print head? colors
true
Индекс переменной colors в первой позиции индекса блока.
print index? colors
1
Блок имеет длину в три значения:
print length? colors
3
Первый элемент в блоке:
print first colors
red
Второй элемент в блоке:
print second colors
green
ы можете изменить положение индекса/позиции переменной colors в блоке с помощью различных функций. Чтобы переместить переменную цветов на следующую позицию в блоке цветов, используйте функцию next:
colors: next colors
Функция next перемещает индекс вперёд, на одно значение в блоке и возвращает значение на этой позиции, в качестве результата. Переменная colors теперь установлено в этой новой позиции:

Положение переменной colors изменилось. Теперь переменная больше не находится в голове (head) блока:
print head? colors
false
Он находится на второй позиции в блоке:
print index? colors
2
Однако, если вы получите первый предмет цветов, вы получите:
print first colors
green
Положение значения, возвращаемого функцией first, зависит от положения, которое цвета имеют в блоке. Возвращаемое значение - это не первый цвет в блоке, а первый цвет, следующий сразу за текущей позицией блока.
Точно так же, если вы спросите длину или второй цвет, вы обнаружите, что они также относительны:
print length? Colors
2
print second colors
blue
Вы можете перейти к следующей позиции и получить аналогичный набор результатов:
colors: next colors
print index? colors
3
print first colors
blue
print length? colors
1
Блок-схема теперь выглядит так::

Индекс в переменной colors теперь указывает на последний цвет в блоке, но это ещё не в положение хвоста.
print tail? colors
false
Чтобы дотянуться до хвоста, его нужно переместить в следующую позицию:
colors: next colors
Теперь индекс переменной colors находится в хвосте блока. Он больше не имеет допустимого цвета(значения). Это за концом блока.

Если вы попробуете свой код, вы получите:
print tail? colors
true
print index? colors
4
print length? Colors
0
print first colors
** Ошибка сценария: за пределами допустимого диапазона или за пределом.
** Где: print first colors
В последнем случае вы получите сообщение об ошибке, потому что, когда вы пройдёте конец блока, нет действительного первого элемента.
Также возможно перемещение назад в блоке. Если вы напишете:
colors: back colors
вы переместите переменную colors назад на одну позицию в серии:

Все тот же код будет работать как раньше:
print index? colors
3
print first colors
blue
1.2 Пропуск вокруг
Предыдущие примеры перемещаются по серии по одному элементу за раз. Однако бывают случаи, когда вы хотите пропустить несколько элементов, используя функцию skip. Предположим, что переменная colors находится в начале ряда:

Вы можете пропустить два пункта, используя:
colors: skip colors 2
Функция skip аналогична функции next в том, что skip возвращает серию с новой позицией индекса.

Следующий код подтверждает новую позицию:
print index? colors
3
print first colors
blue
Чтобы двигаться назад, используйте skip с отрицательным значениям:
colors: skip colors -1
Это похоже на back. В приведённом выше примере пропуск -1 возвращает индекс на один элемент назад.

print first colors
green
Обратите внимание, что вы не можете пропустить хвост или начало серии. Если вы попытаетесь это сделать, пропустите только элементы серии на столько, насколько это возможно. Это не вызовет ошибки.
Если вы пропустите слишком далеко вперёд, команда skip вернёт конец серии:
colors: skip colors 20
print tail? colors
true
Если вы выполните skip слишком далеко назад, то skip возвращает индекс в начало серии:
colors: skip colors -100
print head? colors
true
Для того, чтобы перейти непосредственно к главе серии, используйте функцию head:
colors: head colors
print head? colors
true
print first colors
red
Вы можете вернуться к хвосту с помощью функции tail:
colors: tail colors
print tail? colors
true
1.3 Извлечение значений
Некоторые из предыдущих примеров использовали first(первое) и second(второе) порядковые функции для извлечения определённых значений из ряда. Полный набор порядковых функций:
first (первый)
second (второй)
third (третий)
fourth (четвёртый)
fifth (пятый)
last (последний_
Порядковые функции предоставляются для удобства и используются для выбора значений из наиболее распространённой позиции в серии. Вот некоторые примеры:
colors: [red green blue gold indigo teal]
print first colors
red
print third colors
blue
print fifth colors
indigo
print last colors
teal
Чтобы извлечь из числовой позиции, используйте функцию pick:
print pick colors 3
blue
print pick colors 5
indigo
Сокращённое обозначение для выбора - использовать путь (через слеш):
print colors/3
blue
print colors/5
indigo
Помните, как показано ранее, извлечение выполняется относительно указанной вами переменной ряда (индекса). Если бы индекс переменной colors находился бы на другом месте в серии, результаты были бы другими.
Извлечение значения за концом его ряда генерирует ошибку в случае порядковых функций и не возвращает ничего (none) в случае функции pick или пути выбора:
print pick colors 10
none
print colors/10
none
1.4 Извлечение подсерии
Вы можете извлечь несколько значений из ряда с помощью функции copy(копирования). Для этого используйте copy с уточнением /part, которое указывает количество значений, которые вы хотите извлечь:
colors: [red green blue]
sub-colors: copy/part colors 2
probe sub-colors
[red green]
Графически это выглядело бы так:

Чтобы скопировать подсерию из любой позиции в серии, сначала перейдите в исходную позицию (установите индекс). В следующем примере перед копированием выполняется переход ко второй позиции в серии с помощью команды next:
sub-colors: copy/part next colors 2
probe sub-colors
[green blue]
Это можно представить как:

Длина копируемой серии может быть указана как конечная позиция, а также как количество копий. Обратите внимание, что позиция указывает, где должна остановиться копия, а не конечная позиция.
probe copy/part colors next colors
[red]
probe copy/part colors back tail colors
[red green]
probe copy/part next colors back tail colors
[green]
Это может быть полезно, когда конечная позиция найдена в результате функции find:
file: %image.jpg
print copy/part file find file "."
image
1.5 Вставка и добавление
ы можете вставить одно или несколько новых значений в любую часть ряда с помощью функции insert. Когда вы вставляете значение в позицию в ряду, пространство создаётся за счёт смещения его предыдущих значений в сторону конца ряда.
Например, блок:
colors: [red green]
будет отображаться как:

Чтобы вставить новое значение в начало блока, где сейчас расположен индекс переменной colors:
insert colors 'blue
Слова red и green сдвинулись в право, и слово blue(в начале которого одинарная кавычка, потому что это слово и не должно быть оценено) вставляются во главе списка.

Обратите внимание, что индекс переменной colors остаётся в начале списка.
probe colors
[blue red green]
Также обратите внимание, что возврат из функции insert не использовался, потому что он не был установлен для перемен:
colors: insert colors 'blue
эффект на блок был бы таким же, но положение индекса переменной colors изменилось бы в результате установки возвращаемого значения. Позиция, возвращаемая при вставке, следует сразу за точкой вставки.

Вставка может быть сделана в любом месте серии. Положение вставки может быть указано, и она может включать хвост. Вставка в хвост имеет эффект добавления к серии.
colors: tail colors
insert colors 'gold
probe colors
[blue red green gold]
Перед вставкой:

после вставки:

Слово gold было вставлено в конце серии.
Другой способ вставить в конец ряда - использовать функцию append. Функция добавления работает так же, как и insert, но всегда вставляет в конце. Предыдущий пример будет выглядеть так:
append colors 'gold
Результат такой же, как и в предыдущем примере.
Функции insert и append также могут принимать блок аргументов для вставки. Например:
colors: [red green]
insert colors [blue yellow orange]
probe colors
[blue yellow orange red green]
Если вы хотите вставить новые значения между red и green словами:
colors: [red green]
insert next colors [blue yellow orange]
probe colors
[red blue yellow orange green]
Функции insert и append имеют другие возможности, которые более подробно рассматриваются в следующем разделе.
1.6 Удаление значений
Вы можете удалить одно или несколько значений из любой части ряда с помощью функции remove.
Для примера начнём со следующего блока:
colors: [red green blue gold]
Как показано здесь:

Вы можете удалить первое значение из блока строкой:
remove colors
Блок станет таким:

Его можно распечатать с помощью:
probe colors
[green blue gold]
Функция remove удаляет значения относительно положения индекса переменной colors. Вы можете удалить значения из любого места в серии, установив позицию.
remove next colors
Блок сейчас:

Несколько значений можно удалить, указав уточнение /part.
remove/part colors 2
Это удаляет оставшиеся значения, оставляя пустой блок:

Как и с insert/part, аргумент для remove/part также может быть позицией внутри блока.
Удаление всех оставшихся значений - обычная операция. Функция clear предназначена для того, чтобы сделать это более простым. Clear удаляет все значения от текущей позиции до хвоста. Например:
Colors: [blue red green gold]
Выглядит это так:

Все после синего(blue) можно удалить с помощью:
clear next colors
Тогда блок станет таким:

Вы можете легко очистить весь блок с помощью:
clear colors
1.7 Изменение значений
Предусмотрен один дополнительный набор функций для изменения значений в серии. Функция change заменяет одно или несколько значений новыми значениями. Хотя этого можно достичь путём удаления и вставки значений, более эффективно использовать change..
Определение блока:
colors: [blue red green gold]

Его второе значение можно изменить строчкой:
change next colors 'yellow
И блок станет такой:

Теперь напечатаем блок:
probe colors
[blue yellow green gold]
Функция poke позволяет указать, что изменение происходит в определённой позиции относительно индекса переменной colors. Функция pick аналогична функции pick, описанной ранее.
poke colors 3 'red
Теперь блок:

И выведем его:
probe colors
[blue yellow red gold]
Функция change имеет дополнительные уточнения, которые описаны далее в этой главе.
2. Функции серии
Вот сводка функций, которые работают с сериями. Большинство из них было подробно описано в предыдущем разделе. Другие будут рассмотрены более подробно в этом разделе.
2.1 Функции создания
|
Функция
|
Описание
|
|---|
|
make
|
Создаёт новую серию данного типа.
|
|
copy
|
Копирует серию.
|
2.2 Функции навигации
|
Функция
|
Описание
|
|---|
|
next
|
Возвращает следующую позицию в серии.
|
|
back
|
Возвращает предыдущую позицию в серии.
|
|
head
|
Возвращает позицию заголовка серии.
|
|
tail
|
Возвращает конечную позицию ряда.
|
|
skip
|
Возвращает позицию плюс или минус целое число.
|
|
at
|
Возвращает позицию плюс или минус целое число, но использует ту же индексацию, что и pick.
|
2.3 Информационные функции
|
Функция
|
Описание
|
|---|
|
head?
|
Возвращает true, если индекс находится в начале серии.
|
|
tail?
|
Возвращает true, если индекс находится в конце серии.
|
|
index?
|
Возвращает смещение от заголовка ряда. (индекс)
|
|
length?
|
Возвращает длину серии от текущей позиции.
|
|
offset?
|
Возвращает расстояние между двумя позициями в серии.
|
|
empty?
|
Возвращает true, если с этой позиции серия пуста.
|
2.4 Функции извлечения
|
Функция
|
Описание
|
|---|
|
pick
|
Извлекает одно значение из позиции индекса в серии.
|
|
copy/part
|
Извлекает подсерию из серии.
|
|
first
|
Извлекает первое значение из ряда.
|
|
second
|
Извлекает второе значение из ряда.
|
|
third
|
Извлекает третье значение из ряда.
|
|
fourth
|
Извлекает четвёртое значение из ряда.
|
|
fifth
|
Извлекает пятое значение из ряда.
|
|
last
|
Извлекает последнее значение из ряда.
|
2.5 Функции модификации
|
Функция
|
Описание
|
|---|
|
insert
|
Вставляет значения в ряд.
|
|
append
|
Добавляет значения в конец ряда.
|
|
remove
|
Удаляет значения из серии.
|
|
clear
|
Очищает значения до конца ряда.
|
|
change
|
Изменяет значения в серии.
|
|
poke
|
Изменяет значения в позиции в серии.
|
2.6 Функции поиска
|
Функция
|
Описание
|
|---|
|
find
|
Находит значение в серии.
|
|
select
|
Находит связанное значение в серии.
|
|
replace
|
Ищет и заменяет значения в серии.
|
|
parse
|
Разбирает значения в серии.
|
2.7 Функции сортировки
|
Функция
|
Описание
|
|---|
|
sort
|
Сортирует значения в серии по порядку.
|
|
reverse
|
Изменить порядок значений в серии на обратный
|
2.8 Функции набора данных (группы)
|
Функция
|
Описание
|
|---|
|
unique
|
Возвращает уникальный набор значений, удаляя дубликаты.
|
|
intersect
|
Возвращает только значения, найденные в обеих сериях.
|
|
union
|
Возвращает объединённые значения из двух серий.
|
|
exclude
|
Возвращает одну серию меньше другой.
|
|
difference
|
Возвращает значения, не найденные ни в одной из серий.
|
3. Типы данных серии
Все типы данных серии можно разделить на два больших класса. Каждый включает значение типа данных и функцию проверки типа.
3.1 Типы блоков
|
Тип блока
|
Описание
|
|---|
|
Block!
|
Блоки значений
|
|
Paren!
|
Блоки значений, заключённые в круглые скобки
|
|
Path!
|
Пути
|
|
List!
|
Связанные списки
|
|
Hash!
|
Ассоциативные массивы
|
3.2 Типы строк
|
Тип строки
|
Описание
|
|---|
|
String!
|
Строка символов
|
|
Binary!
|
Строка байт (двоичных данных)
|
|
Tag!
|
HTML и XML теги
|
|
File!
|
Имена файлов
|
|
URL!
|
Адрес интернет ресурсов
|
|
Email!
|
Адрес электронной почты
|
|
Image!
|
Данные изображения
|
|
Issue!
|
Коды последовательности
|
3.3 Псевдотипы
Серийные типы данных сгруппированы в несколько псевдотипов, что упрощает проверку аргументов функций и типов:
|
Псевдотип
|
Описание
|
|---|
|
Series!
|
Тип данных серии
|
|
Any-block!
|
Любой из блочных типов данных
|
|
Any-string!
|
Любой из строковых типов данных
|
3.4 Функции типовых испытаний
Тесты блочного типа:
Block? Paren? Path? List? Hash?
Тесты строкового типа:
String? Binary? Tag? File? URL?
Email? Image? Issue?
Типовые испытания других серий:
Series? Any-block? Any-string?
4. Информация о серии
4.1 Length?
Длина серии - это количество элементов (значений для блока или символов для строки) от текущей позиции (индекса) до конца . Если текущая позиция является заголовком серии, то длина - это количество элементов во всей серии.
Функция length? возвращает количество элементов до хвоста.
colors: [blue red green]
print length? colors
3
Все три значения являются частью длины:

Если положение индекса переменной color продвигается к следующему значению:
color: next color
print length? color
2
То длинна становится равна двум:

Другие примеры с length?:
print length? "Ukiah"
5
print length? []
0
print length? ""
0
data: [1 2 3 4 5 6 7 8]
print length? data
8
data: next data
print length? data
7
data: skip data 5
print length? data
2
4.2 Head?
Голова ряда - это позиция его первого значения. Если индекс серии в голове, то функция head? возвращает true:
data: [1 2 3 4 5]
print head? data
true
data: next data
print head? data
false
4.3 Tail?
Хвостовая часть серии - это позиция, следующая сразу за последним значением. Если переменная ряда находится в хвосте, функция tail? возвращает true:
data: [1 2 3 4 5]
print tail? data
false
data: tail data
print tail? data
true
Функция empty? эквивалентна функции tail?.
print empty? data
true
Если empty? возвращает true, это означает, что между текущей позицией и хвостом нет значений; однако в серии все ещё могут быть значения. Значения могут присутствовать перед текущей позицией. Если вам нужно определить, пуста ли серия от головы до хвоста, используйте:
print empty? head data
false
4.4 Index?
Индекс - положение в серии, относительно головы серии. Чтобы определить позицию индекса для серии, используйте функцию index?:
data: [1 2 3 4 5]
print index? data
1
data: next data
print index? data
2
data: tail data
print index? data
6
4.5 Offset?
Расстояние между двумя позициями в серии можно определить с помощью функции offset?.
data: [1 2 3 4]
data1: next data
data2: back tail data
print offset? data1 data2
4
В этом примере смещение - это разница между позицией 2 и позицией 4:

5. Создание и копирование серий
Новые серии создаются с функциями make и
copy.
Используйте функцию make для создания новой серии на основе типа данных серии и начального размера. Размер - это приблизительный размер, необходимый для серии. Если исходный размер слишком мал, серия автоматически расширится, но с небольшой потерей производительности.
block: make block! 50
string: make string! 10000
list: make list! 128
file: make file! 64
Функция copy создаёт новую серию, копируя существующую серию:
string: copy "Записка запечатана в бутылке"
new-string: copy string
block: copy [1 2 3 4 5]
new-block: copy block
Копирование также важно для использования с функциями, которые изменяют содержимое серии. Например, если вы хотите изменить регистр строки без изменения оригинала, используйте copy: :
string: uppercase copy "Записка запечатана в бутылке"
5.1 Частичные копии
Функция copy имеет уточнение /part, которое принимает один аргумент, являющийся либо целым числом, определяющее количество элементов для копирования, либо позицию в серии, указывающею последнюю позицию для копирования.
str: "Записка запечатана в бутылке"
print str
Записка запечатана в бутылке
print copy/part str find str " "
Записка
new-str: copy/part (find str "запечатана") (find str "бутылке")
print new-str
запечатана в
blk: [ages [10 12 32] sizes [100 20 30]]
new-blk: copy/part blk 2
probe new-blk
[ages [10 12 32]]
5.2 Глубокие копии
Многие блоки содержат другие блоки и строки. Когда такой блок копируется, его подсерии не копируются. Подсерии упоминаются напрямую и представляют собой те же данные серии, что и исходный блок. Если вы измените любую из этих подсерий, вы также измените их в исходном блоке.
В copy/deep уточняющих силах копии всех значений ряда в пределах блока:
blk-one: ["abc" [1 2 3]]
probe blk-one
["abc" [1 2 3]]
Следующий пример присваивает нормальную копию blk-one к blk-two:
blk-two: copy blk-one
probe blk-one
["abc" [1 2 3]]
probe blk-two
["abc" [1 2 3]]
Если изменяется строка или блок, содержащиеся в blk-two, значения серии в blk-one также изменяются..
append blk-two/1 "DEF"
append blk-two/2 [4 5 6]
probe blk-one
["abcDEF" [1 2 3 4 5 6]]
probe blk-two
["abcDEF" [1 2 3 4 5 6]]
Использование copy/deep делает копию всех значений серии, найденных в блоке:
blk-two: copy/deep blk-one
append blk-two/1 "ghi"
append blk-two/2 [7 8 9]
probe blk-one
["abcDEF" [1 2 3 4 5 6]]
probe blk-two
["abcDEFghi" [1 2 3 4 5 6 7 8 9]]
5.3 Начальные копии
При инициализации строки или серии блоков используйте copy, чтобы сделать уникальную серию:
str: copy ""
blk: copy []
Использование copy гарантирует, что новый ряд создаётся для слова каждый раз, когда слово инициализируется. Вот пример того, почему это важно.
print-it: func [/local str] [
str: ""
insert str "ha"
print str
]
print-it
ha
print-it
haha
print-it
hahaha
В этом примере, поскольку copy не использовалась, серия пустых строк изменяется при каждом вызове print-it. Строка series ha вставляется в str каждый раз, когда она вызывается print-it.
Изучение источника функции в том виде, в каком он сейчас существует, выявляет корень проблемы:
source print-it
print-it: func [/local str] [
str: "hahaha"
insert str "ha"
print str
]
Хотя str является локальной переменной, её строковое значение является глобальным. Чтобы избежать этой проблемы, функция copy должна скопировать пустую строку или использовать make в строке.make.
print-it: func [/local str] [
str: copy ""
insert str "ha"
print str
]
print-it
ha
print-it
ha
print-it
ha
6. Итерация серии
Вы можете использовать цикл для обхода серии. Есть несколько функций цикла, которые могут помочь автоматизировать итерационный процесс.
6.1 Foreach
Цикл foreach проходит через серию, устанавливая слово или несколько слов в значения в серии.
Цикл foreach принимает три аргумента: слово или блок слов, содержащий значения для каждой итерации, серию и блок, оцениваемый для каждой итерации.
colors: [red green blue yellow orange gold]
foreach color colors [print color]
red
green
blue
yellow
orange
gold
foreach [c1 c2] colors [print [c1 c2]]
red green
blue yellow
orange gold
foreach [c1 c2 c3] colors [print [c1 c2 c3]]
red green blue
yellow orange gold
Это очень полезно для блоков, которые содержат связанные значения:
people: [
"Bob" bob@example.com 12
"Tom" tom@example.net 40
"Sam" sam@example.org 22
]
foreach [name email age] people [
print [name email age]
]
Bob bob@example.com 12
Tom tom@example.net 40
Sam sam@example.org 22
Обратите внимание, что цикл foreach не продвигает текущий индекс по серии, поэтому нет необходимости сбрасывать его переменную серии.
6.2 While
Наиболее гибкий подход заключается в использовании цикла while, который позволяет делать почти все для серии без проблем.
colors: [red green blue yellow orange]
while [not tail? colors] [
print first colors
colors: next colors
]
red
green
blue
yellow
orange
Показанный ниже метод позволяет вставлять значения, не нажимать дважды:
The method shown below allows you to insert values without
hitting a value twice:
colors: head colors
while [not tail? colors] [
if colors/1 = 'yellow [
colors: insert colors 'blue
]
colors: next colors
]
Этот пример показывает, что insert возвращает позицию сразу после вставки.
Чтобы удалить (remove) значение без случайного пропуска значения, используйте следующий код:
colors: head colors
while [not tail? colors] [
either colors/1 = 'blue [
remove colors
][
colors: next colors
]
]
Обратите внимание, что если удаление выполнено, функция next не выполняется.
6.3 Цикл Forall
Цикл forall похожа на while но устраняет некоторые из требуемых усилий. Цикл forall начинается с текущего индекса и последовательно продвигается к своему хвосту, оценивая блок для каждого значения.
Forall принимает два аргумента: переменную серии и блок, оцениваемый для каждой итерации.
colors: [red green blue yellow orange]
forall colors [print first colors]
red
green
blue
yellow
orange
forall перемещает позицию индекса через ряд, поэтому, когда он заканчивается, индекс остаётся на хвосте:
print tail? colors
true
Следовательно, перед повторным использованием переменную необходимо сбросить:
colors: head colors
Кроме того, если блок изменяет серию, будьте осторожны, чтобы не пропустить или не повторить значение. В некоторых случаях цикл forall может зациклится, поэтому если вы не уверены, используйте while.
forall colors [
if colors/1 = 'blue [remove colors]
print first colors
]
red
green
yellow
orange
6.4 Цикл Forskip
Подобно forall, цикл forskip продвигается по серии, начиная с текущей позиции, но каждый раз пропускает указанное количество значений.
Цикл forskip принимает три аргумента: переменную серии, пропуск между каждой итерацией и блок для оценки для каждой итерации.
colors: [red green blue yellow orange]
forskip colors 2 [print first colors]
red
blue
orange
Цикл forskip оставляет серию в хвосте, требуя, чтобы вы её сбросили.
print tail? colors
true
colors: head colors
6.5 Функция прерывания
Любой из циклов можно остановить в любое время, оценив функцию break (прерывания) из блока оценки/цикла. См. Главу «Выражения» для получения дополнительной информации о функции break.
7. Поиск в серии
Функция find выполняет поиск значения или шаблона в блоках или сериях строк. Эта функция имеет множество усовершенствований, которые позволяют изменять параметры поиска в широком диапазоне.
7.1 Простой поиск
Самый простой и распространённый способ использования find - поиск значения в блоке или строке. В этом случае для поиска требуется только два аргумента: серия для поиска и значение для поиска:
colors: [red green blue yellow orange]
where: find colors 'blue
probe where
[blue yellow orange]
print first where
blue
Функция find также может искать значения по типу данных. Это может быть весьма полезно.
items: [10:30 20-Feb-2000 Cindy "United"]
where: find items date!
print first where
20-Feb-2000
where: find items string!
print first where
United
Пример поиска в строке:
colors: "red green blue yellow orange"
where: find colors "blue"
print where
blue yellow orange
Если поиск не удался, возвращается none.
colors: [red green blue yellow orange]
probe find colors 'indigo
none
7.2 Уточнения в find
В Find есть множество уточнений, которые поддерживают широкий спектр параметров поиска:
|
Уточнение
|
Описание
|
|---|
|
/part
|
Ограничивает поиск в серии заданной продолжительностью или конечной позицией.
|
|
/only
|
Обрабатывает значение ряда как одно значение.
|
|
/case
|
Использует сравнение строк с учётом регистра.
|
|
/any
|
Разрешает использование шаблонов подстановочных знаков, позволяющих проводить сопоставления с любым символом. Звёздочка (*) в шаблоне соответствует любой строке, а вопросительный знак (?) В шаблоне соответствует любому символу.
|
|
/with
|
Позволяет использовать подстановочные знаки шаблона с разными символами, кроме звёздочки (*) и (?). Это позволяет шаблону содержать звёздочки и вопросительные знаки.
|
|
/match
|
Соответствует шаблону, начинающемуся с позиции текущего ряда, а не находит первое вхождение значения или строки. Возвращает позицию хвоста, если совпадение найдено.
|
|
/tail
|
Возвращает хвостовую позицию совпадения при успешном поиске, а не точку, в которой было найдено совпадение.
|
|
/last
|
Поиск совпадения в обратном направлении, начиная с конца серии.
|
|
/reverse
|
Поиск совпадения в обратном направлении, начиная с текущей позиции.
|
7.3 Частичный поиск
Уточнение /part позволяет ограничить часть серии, в которой выполняется поиск. Например, вы можете захотеть ограничить поиск заданной строкой или частью текста.
Подобно insert/part и remove/part,
find/part принимает либо счётчик, либо конечную позицию. В следующем примере используется счетчик и ограничивается поиск первыми тремя элементами:
colors: [red green blue yellow blue orange gold]
probe find/part colors 'blue
[blue yellow blue orange gold]
Следующий поиск ограничен первыми 15 символами:
text: "Keep things as simple as you can."
print find/part text "as" 15
as simple as you can.
В следующем примере используется конечная позиция. Поиск ограничен одной строкой текста:
text: {
This is line one.
This is line two.
}
start: find text "this"
end: find start newline
item: find/part start "line" end
print item
line one.
7.4 Позиция хвоста
Функция find возвращает позицию в серии, где был найден элемент. Уточнение /tail возвращает позицию сразу после пункта , который был найден. Вот пример:
filename: %script.txt
print find filename "."
.txt
print find/tail filename "."
txt
clear change find/tail filename "." "r"
print filename
script.r
В этом примере clear необходимо удалить xt, который следует за t.
7.5 Обратный поиск
Последний пример в предыдущем разделе завершится ошибкой, если в имени файла будет более одной точки. Например:
filename: %new.script.txt
print find filename "."
.script.txt
В этом примере нам нужно последнее вхождение точки в строке, которое можно найти с помощью уточнения /last. В /last уточняющие поиски отсталые через ряд. Уточнение /last выполняет поиск в обратном направлении через ряд.
print find/last filename "."
.txt
Уточнение /last может быть объединено с /tail к производству:
print find/last filename "."
txt
Если вы хотите продолжить поиск в обратном направлении по строке, вам потребуется уточнение /reverse. Это уточнение выполняет поиск от текущей позиции обратно к голове, а не вперёд к хвосту.
where: find/last filename "."
print where
.txt
print find/reverse where "."
.script.txt
Обратите внимание, что /reverse продолжает поиск непосредственно перед позицией последнего совпадения. Это не позволяет ему снова найти тот же период.
7.6 Повторные поиски
Вы легко можете повторить функцию find для поиска нескольких вхождений значения или строки. Вот пример, который напечатает все строки, найденные в блоке:
blk: load %script.r
while [blk: find blk string!] [
print first blk
blk: next blk
]
В следующем примере подсчитывается количество новых строк в скрипте. Он использует уточнение /tail для предотвращения бесконечного цикла и возвращает позицию сразу после совпадения.
text: read %script.r
count: 0
while [text: find/tail text newline] [count: count + 1]
Чтобы выполнить повторный поиск в обратном направлении, используйте уточнение /reverse. В следующем примере печатаются все позиции индекса в обратном порядке для текста сценария.
while [text: find/reverse tail text newline] [
print index? text
]
7.7 Соответствие
Уточнение /match изменяет поведение find для выполнения сопоставления с образцом на текущей позиции ряда. Это уточнение позволяет выполнять операции синтаксического анализа, сопоставляя следующую часть серии с ожидаемыми шаблонами. См. Главу о синтаксическом анализе, чтобы узнать о другом способе сопоставления серий.
Вот простой пример сопоставления:
blk: [1342 "Franklin Pike Circle"]
probe find/match blk integer!
["Franklin Pike Circle"]
probe find/match blk 1432
["Franklin Pike Circle"]
probe find/match blk "test"
none
str: "Keep things simple."
probe find/match str "keep"
" things simple."
print find/match str "things"
none
Обратите внимание, что в этом примере поиск не выполняется. Начало серии либо совпадает, либо нет. Если он совпадает, серия перемещается на позицию, следующую сразу за точкой совпадения, что позволяет сопоставить следующую последовательность.
Вот простой парсер, написанный с помощью find/match:
grammar: [
["keep" "make" "trust"]
["things" "life" "ideas"]
["simple" "smart" "happy"]
]
parse-it: func [str /local new] [
foreach words grammar [
foreach word words [
if new: find/match str word [break]
]
if none? new [return false]
str: next new ;skip space
]
true
]
print parse-it "Keep things simple"
true
print parse-it "Make things smart"
true
print parse-it "Trust life well"
false
Сопоставление можно сделать с учётом регистра с помощью уточнения /case.
Возможность /match может быть значительно расширена добавлением уточнения /any, как описано ниже.
7.8 Поиск по шаблону
Уточнение /any позволяет подстановочные сопоставление с образцом. Знак вопроса (?) И звёздочка (*) действуют как подстановочные знаки для соответствия любому одиночному символу или любому количеству символов соответственно. Уточнение /any может быть использовано в сочетании find с или без /match утонченности.
Примеры:
str: "abcdefg"
print find/any str "c*f"
cdefg
print find/any str "??d"
bcdefg
email-list: [
mack@rebol.dom
judy@somesite.dom
jack@rebol.dom
biff@rebol.dom
jenn@somesite.dom
]
foreach email email-list [
if find/any email *@rebol.dom [print email]
]
mack@rebol.dom jack@rebol.dombiff@rebol.dom
В следующем примере используется уточнение /match, чтобы попытаться сопоставить шаблон со следующей частью серии:
file-list: [
%rebol.exe
%notes.html
%setup.html
%feedback.r
%nntp.r
%rebdoc.r
%rebol.r
%user.r
]
foreach file file-list [
if find/match/any file %reb*.r [print file]
]
rebdoc.rrebol.r
Если какой-либо из подстановочных знаков является частью того, что должно быть сопоставлено, заменяющие подстановочные символы могут быть предоставлены с использованием уточнения /with.
7.9 Select
Полезной разновидностью функции find является функция select, которая возвращает значение, следующее за найденным. Функция select часто используется для поиска значения в помеченных блоках данных. Функция select принимает те же аргументы, что и find: серия для поиска и значение find. Однако, в отличие от find , который возвращает позицию ряда, функция select возвращает значение, следующее за совпадением.
colors: [red green blue yellow orange]
print select colors 'green
blue
Имея простую базу данных, функцию select можно использовать для доступа к её значениям:
email-book: [
"George" harrison@guru.org
"Paul" lefty@bass.edu
"Ringo" richard@starkey.dom
"Robert" service@yukon.dom
]
Следующий код находит адрес электронной почты соответствующий конкретному имени:
print select email-book "Paul"
lefty@bass.edu
Используйте функцию select, чтобы найти блок выражений для оценки. Например, учитывая следующие данные:
cases: [
10 [print "ten"]
20 [print "twenty"]
30 [print "thirty"]
]
блок можно оценить на основе селектора:
do select cases 10
ten
do select cases 30
thirty
7.10 Поиск и замена
Чтобы заменить значения в серии, вы можете использовать функцию replace. Эта функция ищет определённое значение в серии, а затем заменяет его новым значением.
Функция replace принимает три аргумента: серию для поиска, значение для замены и новое значение.
str: "hello world hello"
probe replace str "hello" "aloha"
"aloha world hello"
data: [1 2 8 4 5]
probe replace data 8 3
[1 2 3 4 5]
probe replace data 4 `four
[1 2 3 four 5]
probe replace data integer! 0
[0 2 3 four 5]
Используйте уточнение /all, чтобы заменить все вхождения значения от текущей позиции до хвоста.
probe replace/all data integer! 0
[0 0 0 four 0]
code: [print "hello" print "world"]
replace/all code 'print 'probe
probe code
[probe "hello" probe "world"]
do code
helloworld
str: "hello world hello"
probe replace/all str "hello" "aloha"
"aloha world aloha"
8. Сортировка серий
Функция sort предлагает простой и быстрый метод сортировки серий. Это наиболее полезно для блоков данных, но также может использоваться для строк символов.
8.1 Простая сортировка
Простые примеры сортировки:
names: [Ева Люк Зафод Адам Мэтт Бетти]
probe sort names
[Адам Бетти Ева Зафод Люк Мэтт]
print sort [321.3 78 321 42 321.8 12 98]
12 42 78 98 321 321.3 321.8
print sort "plosabelm"
abellmops
Обратите внимание на то, что sort разрушительна для своей серии аргументов. Он переупорядочивает исходные данные. Чтобы предотвратить это, используйте copy, как в следующем примере:
probe sort copy names
По умолчанию при сортировке регистр не учитывается:
print sort ["Fred" "fred" "FRED"]
Fred fred FRED
print sort "G4C28f9I15Ed3bA076h"
0123456789AbCdEfGhI
Уточнение /case делает сортировку с учётом регистра:
print sort/case "gCcAHfiEGeBIdbFaDh"
ABCDEFGHIabcdefghi
print sort/case ["Fred" "fred" "FRED"]
FRED Fred fred
print sort/case "g4Dc2BI8fCF9i15eAd3bGaE07H6h"
0123456789ABCDEFGHIabcdefghi
Можно отсортировать многие другие типы данных:
print sort [1.3.3.4 1.2.3.5 2.2.3.4 1.2.3.4]
1.2.3.4 1.2.3.5 1.3.3.4 2.2.3.4
print sort [$4.23 $23.45 $62.03 $23.23 $4.22]
$4.22 $4.23 $23.23 $23.45 $62.03
print sort [11:11:43 4:12:53 4:14:53 11:11:42]
4:12:53 4:14:53 11:11:42 11:11:43
print sort [11-11-1999 10-11-9999 11-4-1999 11-11-1998]
11-Nov-1998 11-Apr-1999 11-Nov-1999 10-Nov-9999
print sort [john@doe.dom jane@doe.dom jack@jill.dom]
jack@jill.dom jane@doe.dom john@doe.dom
print sort [%user.r %rebol.r %history.r %notes.html]
history.r notes.html rebol.r user.r
8.2 Групповая сортировка
Часто бывает необходимо отсортировать набор данных, который имеет более одного значения на запись. Уточнении /skip применяется для сортировки таких записей, которые имеют фиксированную длину. Уточнение принимает один дополнительный аргумент: целое число, определяющее длину каждой записи.
Вот пример сортировки блока, который содержит имя, фамилию, возраст и адрес электронной почты. Блок сортируется по его первому столбцу, имени.
names: [
"Evie" "Jordan" 43 eve@jordan.dom
"Matt" "Harrison" 87 matt@harrison.dom
"Luke" "Skywader" 32 luke@skywader.dom
"Beth" "Landwalker" 104 beth@landwalker.dom
"Adam" "Beachcomber" 29 adam@bc.dom
]
sort/skip names 4
foreach [first-name last-name age email] names [
print [first-name last-name age email]
]
Adam Beachcomber 29 adam@bc.dom
Beth Landwalker 104 beth@landwalker.dom
Evie Jordan 43 eve@jordan.dom
Luke Skywader 32 luke@skywader.dom
Matt Harrison 87 matt@harrison.dom
8.3 Функции сравнения
Уточнение /compare позволяет выполнять пользовательские сравнения для сортировки данных. Это уточнение принимает дополнительный аргумент - функцию сравнения, используемую для упорядочивания данных.
Функция сравнения записывается как обычная функция, которая принимает два аргумента. Эти аргументы являются значениями для сравнения. Функция сравнения возвращает true (истина), если первое значение следует поместить перед вторым значением, и false (ложь), если первое значение следует поместить после второго значения.
При обычном сравнении данные располагаются в порядке возрастания:
ascend: func [a b] [a < b]
Если первое значение меньше второго, функция возвращает true (истину), и первое значение помещается перед вторым значением.
data: [100 101 -20 37 42 -4]
probe sort/compare data :ascend
[-20 -4 37 42 100 101]
Так же:
descend: func [a b] [a > b]
Если первое значение больше второго, возвращается true, и данные сначала сортируются с более высокими значениями. Сортировка будет происходить от больших значений.
probe sort/compare data :descend
[101 100 42 37 -4 -20]
Обратите внимание, что в обоих случаях функция сравнения передаётся с указанием имени с двоеточием. Имя, которому предшествует двоеточие, приводит к тому, что функция передаётся на сортировку без предварительной оценки. Функция сравнения также может быть предоставлена напрямую:
probe sort/compare data func [a b] [a > b]
[101 100 42 37 -4 -20]
9. Серии как наборы данных
Есть несколько функций, которые работают с сериями как с наборами данных. Эти функции позволяют выполнять такие операции, как поиск объединения или пересечения двух серий.
9.1 Unique (Уникальный)
Функция unique возвращает уникальный набор, который не содержит повторяющихся значений.
Примеры:
data: [Bill Betty Bob Benny Bart Bob Bill Bob]
probe unique data
[Bill Betty Bob Benny Bart]
print unique "abracadabra"
abrcd
9.2 Intersect (Пересечение)
Функция intersect принимает две серии и возвращает серию, содержащую значения, присутствующие в обеих сериях.
Примеры:
probe intersect [Bill Bob Bart] [Bob Ted Fred]
[Bob]
lunch: [ham cheese bread carrot]
dinner: [ham salad carrot rice]
probe intersect lunch dinner
[ham carrot]
print intersect [1 3 2 4] [3 5 4 6]
3 4
string1: "CBAD" ; A B C D scrambled
string2: "EDCF" ; C D E F scrambled
print sort intersect string1 string2
CD
Пересечение можно найти между битовыми наборами:
all-chars: "ABCDEFGHI"
charset1: charset "ABCDEF"
charset2: charset "DEFGHI"
charset3: intersect charset1 charset2
print find charset3 "E"
true
print find charset3 "B"
false
Уточнение /case выполняет регистрозависимое пересечение:
probe intersect/case [Bill bill Bob bob] [Bart bill Bob]
[bill Bob]
9.3 Union (Объединение)
Функция union принимает две серии и возвращает серию, которая содержит все значения из обеих серий, но не дублирует.
Примеры:
probe union [Bill Bob Bart] [Bob Ted Fred]
[Bill Bob Bart Ted Fred]
lunch: [ham cheese bread carrot]
dinner: [ham salad carrot rice]
probe union lunch dinner
[ham cheese bread carrot salad rice]
print union [1 3 2 4] [3 5 4 6]
1 3 2 4 5 6
string1: "CBDA" ; A B C D scrambled
string2: "EDCF" ; C D E F scrambled
print sort union string1 string2
ABCDEF
Функция union также может быть использована с битовыми наборами:
charset1: charset "ABCDEF"
charset2: charset "DEFGHI"
charset3: union charset1 charset2
print find charset3 "C"
true
print find charset3 "G"
true
Уточнение /case позволяет регистрозависимые союзы:
probe union/case [Bill bill Bob bob] [bill Bob]
[Bill bill Bob bob]
9.4 Exclude (Исключить)
Функция exclude принимает две серии и возвращает серию, которая содержит все значения первой серии за вычетом значений второй.
probe exclude [1 2 3 4] [1 2 3 5]
[4]
probe exclude [Bill Bob Bart] [Bob Ted Fred]
[Bill Bart]
lunch: [ham cheese bread carrot]
dinner: [ham salad carrot rice]
probe exclude lunch dinner
[cheese bread]
string1: "CBAD" ; A B C D scrambled
string2: "EDCF" ; C D E F scrambled
print sort difference string1 string2
AB
Уточнение /case позволяет выполнить регистрозависимое исключение:
probe exclude/case [Bill bill Bob bob] [Bart bart bill Bob]
[Bill bob]
9.5 Difference (Разница)
Функция difference принимает две серии и возвращает серию, которая содержит все значения, не совпадающие с обеими сериями.
Примеры:
probe difference [1 2 3 4] [1 2 3 5]
[4 5]
probe difference [Bill Bob Bart] [Bob Ted Fred]
[Bill Bart Ted Fred]
lunch: [ham cheese bread carrot]
dinner: [ham salad carrot rice]
probe difference lunch dinner
[cheese bread salad rice]
string1: "CBAD" ; A B C D scrambled
string2: "EDCF" ; C D E F scrambled
print sort difference string1 string2
ABEF
Уточнение /case позволяет регистрозависимые различия.
probe difference/case [Bill bill Bob bob] [Bart bart bill Bob]
[Bill bob Bart bart]
9.6 Exclude (Исключить)
Разновидностью функции difference является функция exclude. Она возвращает значения, которые находятся в первой серии, но не найдены во второй серии. Например:
probe exclude [1 2 3 4] [1 2 3 5]
[4]
Обратите внимание, что приведённый выше результат не содержит 5, как это было в случае с difference ( разница) в предыдущем разделе.
probe exclude [Bill Bob Bart] [Bob Ted Fred]
[Bill Bart]
probe exclude "abcde" "ace"
"bd"
10. Переменные нескольких серий
Несколько переменных могут относиться к одной и той же серии. Например:
data: [1 2 3 4 5]
start: find data 3
end: find start 4
print first start
2
print first end
4
И переменная start, и переменная end относятся к серии. У них разные позиции, но серия, на которую они ссылаются, одна.

Если для серии выполняется функция insert (вставить) или remove (удалить), то значения в серии сдвигаются, и переменные start и end могут больше не относиться к одним и тем же значениям. Например, если значение удаляется из серии в начальной позиции:
remove start
print first start
3
print first end
5
Ряд сдвинулся влево, и теперь переменные относятся к разным значениям.

Обратите внимание, что позиции индекса переменных не изменились, но значения в серии изменились. Такая же ситуация может возникнуть при использовании insert (вставки).
Иногда этот побочный эффект будет работать вам на пользу. Иногда этого не происходит, и вам нужно будет исправить это в своем коде.
11. Уточнения модификации
Функции change (изменение), insert (вставка) и remove (удаление) могут потребовать дополнительных уточнений, чтобы откорректировать их работу.
11.1 Part
Уточнение /part принимает подсчёт или позицию в серии и использует её, чтобы ограничить эффект функции.
Например, используя следующую серию:
str: "abcdef"
blk: [1 2 3 4 5 6]
вы можете изменить часть str и blk, используя change/part:
change/part str [1 2 3 4] 3
probe str
1234def
change/part blk "abcd" 3
probe blk
["abcd" 4 5 6]
Вы можете вставить часть серии в хвост str и blk с помощью insert/part.
insert/part tail str "-ghijkl" 4
probe str
1234def-ghi
insert/part tail blk ["--" 7 8 9 10 11 12] 4
probe blk
["abcd" 4 5 6 "--" 7 8 9]
Чтобы удалить часть серий str и blk, используйте remove/part. Обратите внимание, как find используется для получения позиции в серии:
remove/part (find str "d") (find str "-")
probe str
1234-ghi
remove/part (find blk 4) (find blk "--")
probe blk
["abcd" "--" 7 8 9]
11.2 Only
Уточнение /only позволяет изменять или вставлять блок в виде блока, а не его отдельных значений.
Примеры:
blk: [1 2 3 4 5 6]
Вы можете заменить 2 в blk блоком [a b c] и вставить блок [$1 $2 $3] в позицию 5.
change/only (find blk 2) [a b c]
probe blk
[1 [a b c] 3 4 5 6]
insert/only (find blk 5) [$1 $2 $3]
probe blk
[1 [a b c] 3 4 [$1.00 $2.00 $3.00] 5 6]
11.3 Dup
Уточнение /dup вставляет значение заданное число раз.
Примеры:
str: "abcdefghi"
blk: [1 2 3 4 5 6]
Вы можете изменить первые четыре значения в строке или серии блоков на звездочку (*) с помощью:
change/dup str "*" 4
probe str
****efghi
change/dup blk "*" 4
probe blk
["*" "*" "*" "*" 5 6]
Чтобы вставить дефис (-) четыре раза перед последним значением в строке или блоке:
insert/dup (back tail str) #"-" 4
probe str
****efgh----i
insert/dup (back tail blk) #"-" 4
probe blk
["*" "*" "*" "*" 5 #"-" #"-" #"-" #"-" 6]
|