Выражения

Синтаксис

В данной статье при описании выражений приняты следующие обозначения:

  • Элементы выражений разделены тильдой.

  • Круглые скобки служат для группировки элементов выражения.

  • Если в выражении используется литерал скобок или других символов, они заключаются в кавычки: "(". "NEWLINE" обозначает перевод строки.

  • Квантификаторы после элементов и групп обозначают количество повторений:

    • ? — элемент необязателен, может отсутствовать в выражении;

    • + — элемент обязателен и может повторяться в выражении несколько раз;

    • * — элемент может отсутствовать или повторяться несколько раз.

Используйте VRL-песочницу, чтобы проверить работу программы.

Комментарий

Комментарий используется для целей документирования программного кода и обозначается символом #. Каждая строка комментария должна начинаться с символа #. В настоящее время VRL не поддерживает многострочные комментарии.

Примеры

Пример 1. Комментарий из одной строки
# Однострочный комментарий.
Пример 2. Комментарий из нескольких строк
# Первая строка комментария.
# Вторая строка комментария.

Ключевые слова

Ключевые слова — это зарезервированные слова, используемые для базовых функций языка, таких как работа с условиями (if). Они не могут использоваться для наименования переменных или других пользовательских директив. Следующие слова зарезервированы:

  • abort

  • as

  • break

  • continue

  • else

  • false

  • for

  • if

  • impl

  • in

  • let

  • loop

  • null

  • return

  • self

  • std

  • then

  • this

  • true

  • type

  • until

  • use

  • while

Пробелы

Пробел — это любая непустая строка, определенная свойством Unicode White_Space.

VRL является языком свободной формы, что означает, что все пробелы и отступы используются только для разделения токенов в грамматике и не влияют на семантику программы.

Литералы

Пустое значение (Null)

Литерал пустого значения представляет отсутствие определенного значения.

Пример 3. Пример
null

Логическое значение (Boolean)

Литерал типа логическое значение представляет собой двоичное значение, которое может быть только истинным (true) или ложным (false).

Примеры

Пример 4. Истина
true
Пример 5. Ложь
false

Целое число (Integer)

Литерал типа целое число — это десятичное представление 64-битного целого числа со знаком.

Ограничения

Целые числа в VRL могут находиться в диапазоне от -263 + 1 до 263 - 1. Числа за пределами этого диапазона "оборачиваются", то есть переносятся на другой конец диапазона.

Подчеркивание

В целых числах может использоваться символ _ для улучшения читаемости, например, для разделения разрядов. Например, 1_000_000.

Пример

Пример 6. Исходный код
1_000_000
Пример 7. Результат
1000000

Число с плавающей точкой (Float)

Литерал типа число с плавающей точкой представляет собой десятичное представление 64-битного числа с плавающей точкой (в частности, тип "binary64", определенный в IEEE 754-2008), включая знак.

Десятичный литерал с плавающей точкой состоит из целой части (десятичные цифры), десятичной точки и дробной части (десятичные цифры).

Пример 8. Пример
1.001

Ограничения

Числа с плавающей точкой в VRL могут находиться в диапазоне от -1.7976931348623157E+308f64 до 1.7976931348623157E+308f64. Числа за пределами этого диапазона переносятся на другой конец диапазона.

Подчеркивания

В числах с плавающей точкой может использоваться символ _ для улучшения читаемости, например, для разделения разрядов. Например, 1_000_000.0.

Пример

Пример 9. Исходный код
1_000_000.01
Пример 10. Результат
1000000.01

Метка времени (Timestamp)

Литерал метки времени — это нативная метка времени, выраженная в формате RFC 3339 с точностью до наносекунды.

Метки времени определяются с помощью символа t и заключаются в одинарные кавычки (t'2021-02-11T10:32:50.553955473Z').

Примеры

t'2021-02-11T10:32:50.553955473Z'
t'2021-02-11T10:32:50.553Z'
t'2021-02-11T10:32:50.553-04:00'

Часовые пояса

Как определено в формате RFC 3339, литералы меток времени поддерживают UTC и локальные смещения времени.

Строка (String)

Литерал строки представляет собой строку, закодированную в UTF-8. Строковые литералы могут быть сырыми или интерпретированными:

  • Сырые (raw) строковые литералы состоят из неинтерпретированных (неявно закодированных в UTF-8) символов между одиночными кавычками и обозначаются символом s (s'…​'). Обратная косая черта не имеет специального значения в сырых литералах, и такой литерал может содержать символы новой строки.

  • Интерпретированные строковые литералы представляют собой последовательности символов между двойными кавычками ("…​"). Внутри кавычек может находиться любой символ, кроме неэкранированного символа новой строки и неэкранированной двойной кавычки. Текст между двойными кавычками представляет собой результат литерала, с экранированными символами, интерпретируемыми как показано ниже.

Примеры

Пример 11. Строка с символами UTF-8
"Hello, world! 🌎"
Пример 12. Сырая строка
s'Hello, world!'
Пример 13. Сырая строка, содержащая кавычки
s'{ "foo": "bar" }'

Экранирование

Специальные символы, такие как символы новой строки, могут быть выражены с помощью экранирования обратной косой чертой.

Представление Описание

\u{7FFF}

Символ Unicode из 24 бит (до 6 цифр)

\n

Перевод строки

\r

Возврат каретки

\t

Табуляция

\\

Обратная косая черта

\0

Пустой символ

\"

Двойная кавычка

\'

Одиночная кавычка

\{

Фигурная скобка

Шаблоны

Строку можно шаблонизировать с помощью Handlebars. Для этого имя переменной заключается в {{…​}}. Значение переменной вставляется в строку на этой позиции во время выполнения. Поддерживаются только переменные. Переменная должна быть строкой. Чтобы вставить двойные фигурные скобки в строку, их можно экранировать с помощью обратной косой черты: \{{…​\}}.

Чтобы вставить путь из события, сначала присвойте его переменной.

Пример

Пример 14. Исходный код
planet = "Earth"
"Hello, {{ planet }}!"
Пример 15. Результат
"Hello, Earth!"

Многострочные литералы

Длинные строки можно разбить на несколько строк, добавив обратную косую черту перед символом новой строки. Символ новой строки и любые пробелы в начале следующей строки не будут включены в строку.

Пример 16. Пример
"Hello, \
world!"

Конкатенация

Строки можно объединять с помощью оператора +.

Недопустимые символы

Недопустимые последовательности UTF-8 заменяются символом .

Регулярное выражение (Regex)

Литерал регулярного выражения представляет собой регулярное выражение, используемое для сопоставления и разбора строк.

Регулярные выражения определяются с помощью символа r и заключаются в одинарные кавычки: r'…​'. Используется синтаксис регулярных выражений Rust.

Для изучения регулярных выражений в VRL рекомендуется использовать редактор и тестер выражений Rustexp.

Обычные и специальные символы

Представление Описание Эквиваленты

a

Большинство символов представляют сами себя.

\x61

\u0061

\U00000061

\\

Специальные символы [ ] \ / ^ $ . | ? * + ( ) { } для представления самих себя должны быть экранированы.

\x5C

\x61

Шестнадцатеричный код символа ASCII из двух цифр.

a

\u0062

Шестнадцатеричный код символа Unicode из четырех цифр.

b

\U00000062

Шестнадцатеричный код символа Unicode из восьми цифр.

c

\x{00003A9} \u{000003A9} \U{3A9}

Любой шестнадцатеричный код, которому соответствует символ Unicode.

Ω

\t

Символ горизонтальной табуляции.

\x09

\n

Символ перевода строки

\x0A

\r

Символ возврата каретки.

\x0D

\v

Символ вертикальной табуляции.

\x0B

\a

Символ звукового сигнала.

\x07

\f

Символ смены страницы.

\x0C

Метасимволы и специальные символьные классы

Представление Описание Эквиваленты

.

Метасимвол, обозначающий любой символ, кроме символа перевода строки \n.

\p{Property}

Любой символ со свойством Unicode, указанным в фигурных скобках.

Список поддерживаемых свойств описан в документе.

\P{Property}

Любой символ, не имеющий свойства Unicode, указанного в фигурных скобках.

\pX

Любой символ Unicode, относящийся к классу, обозначенному одной буквой:

  • L — буквенные символы: графемы всех письменностей;

  • M — диакритические символы;

  • N — цифры;

  • P — знаки препинания;

  • S — знаки валют, математические и иные обозначения;

  • Z — пробельные символы, разделители строк и абзацев;

  • C — управляющие символы, символы из областей для частного использования и нераспределенных областей.

\p{Property}

\PX

Любой символ Unicode, не относящийся к классу, обозначенному одной буквой.

\P{Property}

[[:ascii:]]

Любой символ ASCII.

[\x00-\x7F]

[[:print:]]

Любой символ ASCII, доступный для печати: любой символ, кроме управляющих.

[ -~]

[[:graph:]]

Любой отображаемый символ ASCII: любой символ, кроме управляющих и пробельных.

[!-~]

\w

Любой символ Unicode, входящий в состав слов: буква или идеограмма любой письменности, диакритический символ, цифра, знак пунктуации, соединяющий слова (например, _), управляющий символ для лигатур.

[\p{Alphabetic}\p{M}\d\p{Pc}\p{Join_Control}]

\W

Любой символ Unicode, не входящий в состав слов.

[^\w]

[[:word:]]

Любая буква базового латинского алфавита, цифра ASCII или подчеркивание.

[0-9A-Za-z_]

(?-u:\w)

[\w&&\p{ascii}]

[[:alnum:]]

Любая буква базового латинского алфавита или цифра ASCII.

[0-9A-Za-z]

[[:alpha:]]

Любая буква базового латинского алфавита.

[A-Za-z]

[[:upper:]]

Любая прописная буква базового латинского алфавита.

[A-Z]

[[:lower:]]

Любая строчная буква базового латинского алфавита.

[a-z]

\d

Любая десятичная цифра Unicode.

\p{Nd}

\D

Любой символ, кроме десятичных цифр Unicode.

[^\d]

[[:digit:]]

Любая десятичная цифра ASCII.

[0-9]

[\d&&\p{ascii}]

(?-u:\d)

[[:xdigit:]]

Любая шестнадцатеричная цифра.

[0-9A-Fa-f]

[[:punct:]]

Любой знак препинания ASCII.

[!-/:@\\\[\]\{\}\(\)~`]

\s

Любой пробельный символ (символ со свойством Unicode Whitespace).

\p{White_Space}

\S

Любой символ, кроме пробельных.

\P{White_Space}

[[:space:]]

Любой пробельный символ ASCII.

[\t\n\v\f\r ]

[[:blank:]]

Пробел или горизонтальная табуляция.

[\t ]

[[:cntrl:]]

Любой управляющий символ ASCII.

[\x00-\x1F\x7F]

Символьные классы и перечисление

Представление Описание Найденные совпадения

xy

Последовательность x и y.

xy

x|y

Перечисление: одна из последовательностей x или y, причем предпочтение отдается x.

x

[xyz]

Объединение: символы из указанных в квадратных скобках.

x, y, z

[^xyz]

Отрицание: все символы, кроме указанных в квадратных скобках.

Все символы, кроме x, y и z.

[a-z]

Диапазон: все символы между указанными.

Символы от a до z включительно.

[x[^xyz]]

Вложенный класс: все символы, указанные хотя бы в одном из классов.

Все символы, кроме y и z.

[a-y&&xyz]

Пересечение: символы, которые входят в оба класса.

x, y

[0-9—​4]

Разность: символы первого класса, которые не входят во второй класс. (Эквивалентно записи [0-9&&[^4]]).

Все десятичные цифры ASCII, кроме 4.

[a-g~~b-h]

Симметрическая разность: символы, которые входят лишь в один класс из указанных.

a, h

Приоритет в перечислениях:

В перечислениях проверяется каждый указанный вариант слева направо, поиск прекращается при первом совпадении.

Пример

Пример 17. Исходный код
.res = parse_regex_all!("authentication", r'authentication|auth', numeric_groups: true)
Пример 18. Результат
[
  {
    "0": "authentication"
  }
]

Здесь функция с шаблоном r'authentication|auth' сначала пытается найти последовательность "authentication", и поскольку она полностью соответствует строке, именно это совпадение и будет возвращено. Однако, если изменить порядок вариантов, изменится и результат.

Пример 19. Исходный код
.res = parse_regex_all!("authentication", r'auth|authentication', numeric_groups: true)
Пример 20. Результат
[
  {
    "0": "auth"
  }
]

При таком порядке вариантов сначала будет найдено "auth". На этом поиск остановится и вернет "auth", несмотря на то, что более длинный вариант "authentication" также соответствует строке.

Порядок вычисления символьных классов:

  1. Диапазоны: выражение r'[а-яё]' равнозначно выражению r'[[а-я]ё]' и выбирает все строчные буквы русского алфавита.

  2. Объединение: выражение r'[ab&&bc]' равнозначно выражению r'[[ab]&&[bc]]' и выбирает символы, которые входят в оба класса.

  3. Пересечение, разность, симметрическая разность имеют одинаковый приоритет и вычисляются по порядку слева направо. Например, следующее выражение:

    r'[\pL--\p\{Greek}&&\p\{Uppercase}]'

    равнозначно такому выражению:

    r'[[\pL--\p\{Greek}]&&\p\{Uppercase}]'

    Эти выражения выбирают все буквенные символы в верхнем регистре, кроме греческих.

  4. Отрицание: выражение r'[^a-z&&[:xdigit:]]' равнозначно выражению r'[^[a-z&&[:xdigit:]]]'.

    Эти выражения выбирают все символы, кроме тех, которые одновременно являются шестнадцатеричными цифрами и строчными латинскими буквами.

Группировка

Группы в круглых скобках определяют области действия флагов, квантификаторов, и перечислений.

Регулярные выражения поддерживают захват групп, что позволяет извлекать части шаблона как строки. Именованные группы захвата позволяют связать результаты извлечения с ключами.

Представление Описание

(exp)

Нумерованная группа захвата.

(?P<name>exp)

Именованная группа захвата. Возможно обращение как по номеру, так и по ключу, указанному в угловых скобках. (Эквивалентно записи (?<name>exp).)

Имя может включать буквенные символы и цифры Unicode, а также символы .,_[] и начинаться с буквенного символа либо подчеркивания.

(?:exp)

Незахватываемая группа.

(?x)

Установка флага x внутри текущей группы.

(?-x)

Выключение флага x внутри текущей группы.

(?x-y:exp)

Установка флага x и выключение флага y внутри незахватываемой группы.

Пример

Рассмотрим следующую функцию:

Пример 21. Исходный код
.res = parse_regex!("2012-12-12", r'(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})')
Пример 22. Результат
{
  "res": {
    "d": "12",
    "m": "12",
    "y": "2012"
  }
}

Данная функция извлекает из строки с датой вида YYYY-MM-DD группы, содержащие год, месяц и число с ключами y, m и d соответственно.

Квантификаторы

Квантификатор после символа, символьного класса или группы определяет, сколько раз может встречаться предшествующее выражение.

При жадной квантификации возвращается наиболее длинная строка из возможных соответствий, при ленивой — наиболее короткая.

Представление Описание Поведение

x?

Ноль или одно повторение x.

Жадная квантификация

x*

Ноль или больше повторений x.

Жадная квантификация

x+

Одно или больше повторений x.

Жадная квантификация

x??

Ноль или одно повторение x.

Ленивая квантификация

x*?

Ноль или больше повторений x.

Ленивая квантификация

x+?

Одно или больше повторений x.

Ленивая квантификация

x{n}

В точности n повторений x. Аналогично записи x{n}?.

x{n,}

Как минимум n повторений x.

Жадная квантификация

x{n,m}

Между n и m повторений x

Жадная квантификация

x{n,}?

Как минимум n повторений x.

Ленивая квантификация

x{n,m}?

Между n и m повторений x

Ленивая квантификация

Примеры

Следующая функция ищет последовательности символов, заключенные в квадратные скобки.

Пример 23. Исходный код
.res = parse_regex_all!("[ERROR] [2024-10-05 10:01:00] [code: 500]", r'\[.*\]', numeric_groups: true)
Пример 24. Результат
[
  {
    "0": "[ERROR] [2024-10-05 10:01:00] [code: 500]"
  }
]

Если заменить квантификатор на ленивый: r'\[.*?\]', функция вернет отдельные подстроки в квадратных скобках.

Пример 25. Исходный код
.res = parse_regex_all!("[ERROR] [2024-10-05 10:01:00] [code: 500]", r'\[.*?\]', numeric_groups: true)
Пример 26. Результат
[
  {
    "0": "[ERROR]"
  },
  {
    "0": "[2024-10-05 10:01:00]"
  },
  {
    "0": "[code: 500]"
  }
]

Позиция в тексте

Следующие символы позволяют указать положение шаблона относительно начала и конца строки, а также границ слов.

Представление Описание

^

Начало текста (в многострочном режиме — начало строки).

$

Конец текста (в многострочном режиме — конец строки).

\A

Только в начале текста, в т. ч. в многострочном режиме.

\z

Только в конце текста, в т. ч. в многострочном режиме.

\b

Граница слова Unicode: символ, соответствующий классу \w с одной стороны, и символ, соответствующий классу \W, либо граница текста, с другой стороны.

\B

Не на границе слова Unicode.

\b{start}, \<

Начало слова Unicode: символ класса \W или начало текста слева, символ класса \w справа.

\b{end}, \>

Конец слова Unicode: символ класса \w слева, символ класса \w или конец текста справа.

\b{start-half}

Проверка начала слова Unicode только слева: символ класса \W или начало текста.

\b{end-half}

Проверка конца слова Unicode только справа: символ класса \W или конец текста.

Примеры

Следующая функция возвращает последовательности алфавитно-цифровых и соединительных символов на границе слова.

Пример 27. Исходный код
.res = parse_regex_all!("@guest, @superuser, @root", r'(?P<user>\b\w+)')
Пример 28. Результат
[
  {
    "user": "guest"
  },
  {
    "user": "superuser"
  },
  {
    "user": "root"
  }
]

Чтобы получить последовательности с символом @, изменим проверку начала слова.

Пример 29. Исходный код
.res = parse_regex_all!("@guest, @superuser, @root", r'(?P<user>\b{start-half}@\w+)')
Пример 30. Результат
[
  {
    "user": "@guest"
  },
  {
    "user": "@superuser"
  },
  {
    "user": "@root"
  }
]

Флаги

Регулярные выражения позволяют использовать флаги — модификаторы, которые изменяют поведение поиска для всего выражения или группы. Флаги могут быть объединены: r'(?ixm)pattern', r'(?im)pattern'. Флаги можно включать и выключать внутри выражения.

Опция Описание Состояние по умолчанию

i

Режим без учета регистра: буквы в выражении соответствуют и прописным, и строчным буквам в строке.

Выключен

m

Многострочный режим:

  • ^ соответствует началу новой строки.

  • $ соответствует концу строки.

Выключен

x

Режим с поддержкой комментариев. Строчные комментарии должны начинаться с символа #.

Пробелы при включенном режиме игнорируются. Чтобы добавить в шаблон пробел, можно использовать экранирование: \ ` или шестнадцатеричный код: \x20.

Выключен

s

Разрешает метасимволу точки . соответствовать символу новой строки \n.

Выключен

U

Меняет местами значение квантификаторов x* и x*? (ленивый режим).

Выключен

u

Поддержка Unicode.

Включен

Примеры

Рассмотрим следующую функцию:

Пример 31. Исходный код
.res = parse_regex!("AaAaAbbBBBb", r'(?i)a+(?-i)b+', numeric_groups: true)
Пример 32. Результат
{
  "0": "AaAaAbb"
}

В начале регулярного выражения включается регистронезависимый режим, поэтому a+ соответствует буквам a и A. Однако b+, после выключения регистронезависимого режима, соответствует только строчной b.

В следующем примере используется захват именованных групп, чтобы изменить формат даты.

Пример 33. Исходный код
replace_with("2022-01-05, 2023-08-25 и 2024-10-18", r'(?x)
  (?P<y>\d{4}) # Год из 4 цифр Unicode.
  -
  (?P<m>\d{2}) # Месяц из 2 цифр Unicode.
  -
  (?P<d>\d{2}) # День из 2 цифр Unicode.
') -> |match| {
    to_string(match.d) + "/" + to_string(match.m) + "/" + to_string(match.y)
}
Пример 34. Результат
"05/01/2022, 25/08/2023 и 18/10/2024"

Массив

Литерал массива представляет собой набор выражений, разделенных запятыми, который создает непрерывный массив. Массив может быть динамически расширен.

Примеры

Пример 35. Пустой массив
[]
Пример 36. Массив из строк
["первый", "второй", "третий"]
Пример 37. Массив из литералов разного типа, включая объект
["смешанный", 1, 1.0, true, false, {"foo": "bar"}]
Пример 38. Вложенные массивы
[
  "первый-уровень",
  [
    "второй-уровень",
    [
      "третий-уровень"
    ]
  ]
]
Пример 39. Массив из динамических выражений
[.поле1, .поле2, to_int!("2"), variable_1]
Пример 40. Массив из динамических выражений
[
  "выражения",
  1 + 2,
  2 == 5,
  true || false
]

Объект

Литерал объекта представляет собой расширяемую структуру "ключ — значение", которая синтаксически эквивалентна JSON-объекту.

Верно сформированный JSON-документ является допустимым объектом VRL.

Примеры

Пример 41. Объект с вложенными массивом и объектом
{
  "поле1": "значение1",
  "поле2": [
      "значение2",
      "значение3",
      "значение4"
   ],
  "поле3": {
    "поле4": "значение5"
  }
}
Пример 42. Массив со значениями, представленными путями и переменными
{
  "поле1": ."некий_путь",
  "поле2": some_variable,
  "поле3": {
    "вложенное_поле": "некое значение"
  }
}

Упорядочивание

Поля объекта упорядочены по ключу в алфавитном порядке по возрастанию. Таким образом, операции, такие как кодирование в JSON, производят строку с ключами, упорядоченными в алфавитном порядке.

Динамические выражения

Переменная

Выражение переменной именует переменные. Название переменной представляет собой последовательность из одной или нескольких букв, цифр и подчеркиваний. Первый символ в названии переменной должен быть буквой или цифрой.

Рекомендуется использовать осмысленные названия переменных.

Синтаксис

first ~ (trailing)*
Элемент О писание

first

Первый символ может быть только латинские буквы в любом регистре и цифры.

trailing

Последующие символы должны содержать только латинские буквы в любом регистре, цифры и подчеркивания.

Примеры

Простая переменная

Пример 43. Исходный код
my_variable = 1
Пример 44. Результат
1

Переменная с путем

Пример 45. Исходный код
my_object = { "one": 1 }
my_object.one
Пример 46. Результат
1

Путь

Выражение пути представляет собой последовательность сегментов, разделенных точками, которые определяют местоположение значения внутри объекта. Ведущая "." означает, что путь указывает на событие. Ведущий "%" означает, что путь указывает на метаданные события.

Синтаксис

root_path ~ path_segments
Элемент Описание

root_path

Все пути должны начинаться с . или %:

  • Символ . представляет корень события.

  • Символ % представляет корень метаданных события.

path_segments

Сегменты пути обозначают сегмент вложенного пути. Каждый сегмент должен быть отделен точкой в начале и может содержать только латинские буквы в любом регистре, цифры и подчеркивания. Сегменты, содержащие символы вне этого диапазона, должны быть заключены в кавычки.

Примеры

Корневой путь события

Пример 47. Событие Vector
{
  "message": "Hello, World!"
}
Пример 48. Исходный код
.
Пример 49. Результат
{
  "message": "Hello, World!"
}

Корневой путь метаданных

Пример 50. Событие Vector
{
  "message": "Hello, World!"
}
Пример 51. Исходный код
%
Пример 52. Результат
{}

Путь верхнего уровня

Пример 53. Событие Vector
{
  "message": "Hello, World!"
}
Пример 54. Исходный код
.message
Пример 55. Результат
Hello, World!

Вложенный путь

Пример 56. Событие Vector
{
  "parent": {
    "child": "Hello, World!"
  }
}
Пример 57. Исходный код
.parent.child
Пример 58. Результат
Hello, World!

Объединение вложенных путей

Пример 59. Событие Vector
{
  "grand_parent": {
    "parent2": {
      "child": "Hello, World!"
    }
  }
}
Пример 60. Исходный код
.grand_parent.parent1.child || .grand_parent.parent2.child
Пример 61. Результат
Hello, World!

Путь в кавычках

Пример 62. Событие Vector
{
  "parent.key.with.special characters": {
    "child": "Hello, World!"
  }
}
Пример 63. Исходный код
."parent.key.with.special characters".child
Пример 64. Результат
Hello, World!

Путь к первому элементу массива

Пример 65. Событие Vector
{
  "массив": [
    "первый",
    "второй"
  ]
}
Пример 66. Исходный код
."массив"[0]
Пример 67. Результат
"первый"

Путь ко второму элементу массива

Пример 68. Событие Vector
{
  "массив": [
    "первый",
    "второй"
  ]
}
Пример 69. Исходный код
."массив"[1]
Пример 70. Результат
"второй"

Индекс

Выражение индекса обозначает элемент массива. Индексы массивов в VRL начинаются с нуля.

Синтаксис

"[" ~ index ~ "]"
Элемент Описание

index

Индекс представляет собой нулевую позицию элемента.

Примеры

Выражение индекса массива

Пример 71. Событие Vector
{
  "массив": [
    "первый",
    "второй"
  ]
}
Пример 72. Исходный код
."массив"[0]
Пример 73. Результат
"первый"

Присваивание

Выражение присваивания присваивает результат выражения справа от знака равенства цели слева (пути или переменной).

Чтобы избежать лишних вычислений, старайтесь минимизировать копирование исходного объекта.

Синтаксис

target ~ ("," ~ error)? ~ operator ~ expression
Аргумент Значение

target

Цель должна быть переменной, индексом или путем. Возможно присваивание сразу нескольким целям, разделенным оператором =.

error

Позволяет необязательное присваивание ошибок, когда выражение справа может возвращать ошибки. Это обычно используется при вызове функций, которые могут возвращать ошибки.

operator

Оператор разделяет target и expression и определяет условия присваивания:

  • = — обычное присваивание;

  • |= — присваивание со слиянием объектов.

expression

Если target — это переменная, expression может быть любым выражением.

Если target — это путь, expression может быть любым выражением, которое возвращает поддерживаемый тип значения объекта (то есть, выражение, не являющееся регулярным).

Примеры

Присваивание пути

Пример 74. Исходный код
.message = "Hello, World!"
Пример 75. Результат
{
  "message": "Hello, World!",
}

Присваивание по вложенному пути

Пример 76. Исходный код
.parent.child = "Hello, World!"

Присваивание элементу массива

Пример 77. Исходный код
.array[1] = "Hello, World!"

Присваивание переменной

Пример 78. Исходный код
my_variable = "Hello, World!"
Пример 79. Результат
"Hello, World!"

Присваивание с возможностью ошибки (успех)

Пример 80. Исходный код
.parsed, .err = parse_json("{\"Hello\": \"World!\"}")
Пример 81. Результат
{
  "parsed": {
    "Hello": "World!"
  }
}

Присваивание с возможностью ошибки (ошибка)

Пример 82. Исходный код
.parsed, .err = parse_json("malformed")
Пример 83. Результат
{
  "err": "malformed"
}

Двойное присваивание

Оператор = может использоваться для присваивания нескольким целям сразу. Двойное присваивание неприменимо, если используется присваивание ошибок.

Пример

Пример 84. Программа VRL
.first = .second = "Hello, World!"
Пример 85. Результат
{
  "first": "Hello, World!",
  "second": "Hello, World!"
}

Присваивание со слиянием

Оператор |= обновляет поля в целевом объекте на основе содержимого объекта из expression. При этом:

  • Поля, которые есть только в целевом объекте, остаются неизменными.

  • Поля, которые есть только во втором объекте, добавляются в целевой.

  • Если поле существует в обоих объектах, значение поля из expression заменяет значение из целевого объекта. Вложенные структуры в таком случае не учитываются.

    Чтобы при слиянии объединить вложенные поля, используйте функцию merge с параметром deep=true.

Пример

Пример 86. Исходный код
my_variable = {
  "parent1": {
    "child1": 1,
    "child2": 2
  },
  "parent2": {
    "child3": 3
  }
}
my_variable |= {
  "parent1": {
    "child2": 4,
    "child5": 5
  }
}
Пример 87. Результат
{
  "parent1": {
    "child2": 4,
    "child5": 5
  },
  "parent2": {
    "child3": 3
  }
}

Арифметическое выражение

Арифметическое выражение выполняет операцию над двумя выражениями (операндами) согласно оператору.

Хотя арифметическое выражение обычно применяется к числам, его можно использовать и с другими типами, такими как строки.

Синтаксис

expression ~ (operator ~ expression)+
Элемент Описание

expression

Выражение может быть любым выражением, которое возвращает тип, допустимый для оператора.

operator

Оператор определяет операцию, выполняемую над операндами слева и справа. Существующие операторы:

  • + — сложение чисел или конкатенация строк;

  • - — вычитание чисел;

  • * — перемножение чисел или повторение строки указанное число раз;

  • / — деление чисел (не целочисленное).

Для нахождения остатка используйте функцию mod.

Пример 88. Исходный код
mod(3, 2)
Пример 89. Результат
1

Примеры

Сложение целых чисел

Пример 90. Исходный код
1 + 1
Пример 91. Результат
2

Сложение чисел с плавающей точкой

Пример 92. Исходный код
0.1 + 0.2
Пример 93. Результат
0.30000000000000004
Некоторые десятичные дроби не могут быть точно представлены в двоичном виде, что приводит к небольшим неточностям в вычислениях (например, 0.1 + 0.2 != 0.3).

Сложение строк

Пример 94. Исходный код
"Hello" + ", " + "World!"
Пример 95. Результат
"Hello, World!"

Вычитание целых чисел

Пример 96. Исходный код
2 - 1
Пример 97. Результат
1

Вычитание чисел с плавающей точкой

Пример 98. Исходный код
2.0 - 1.0
Пример 99. Результат
1

Перемножение целых чисел

Пример 100. Исходный код
2 * 1
Пример 101. Результат
2

Перемножение чисел с плавающей точкой

Пример 102. Исходный код
2.0 * 1.0
Пример 103. Результат
2

Умножение строки на число

Пример 104. Исходный код
"строка" * 2
Пример 105. Результат
"строкастрока"

Деление целых чисел

Пример 106. Исходный код
2 / 1
Пример 107. Результат
2

Деление чисел с плавающей точкой

Пример 108. Исходный код
2.0 / 1.0
Пример 109. Результат
2

Операции над числами разных типов

Арифметические операции над числами разных типов возвращают числа с плавающей точкой.

Примеры

Сложение чисел разных типов

Пример 110. Исходный код
1 + 1.0
Пример 111. Результат
2

Вычитание чисел разных типов

Пример 112. Исходный код
2.0 - 1
Пример 113. Результат
1

Перемножение чисел разных типов

Пример 114. Исходный код
2.0 * 1
Пример 115. Результат
2

Деление чисел разных типов

Пример 116. Исходный код
2.0 / 1
Пример 117. Результат
2

Приоритет операций

Действует стандартный приоритет операций: умножение и деление выполняются до сложения и вычитания. Для изменения приоритета используются скобки.

Примеры

Стандартный приоритет операций

Пример 118. Программа VRL
5 + 6 × 9 - 7
Пример 119. Результат
52

Задание приоритета с помощью скобок

Пример 120. Программа VRL
(5 + 6) × (9 - 7)
Пример 121. Результат
22

Сравнение

Выражение сравнения сравнивает два выражения (операнда) и возвращает логическое значение в соответствии с оператором.

Синтаксис

expression ~ operator ~ expression
Элемент Описание

expression

Операнд может быть любым выражением, которое возвращает тип, допустимый для оператора.

operator

Оператор определяет операцию, выполняемую над операндами слева и справа:

  • == — равно;

  • != — неравно;

  • > — больше;

  • >= — больше или равно;

  • < — меньше;

  • <= — меньше или равно.

Равенство и неравенство

Операторы == и != предназначены для сравнения между собой любых значений. Числовые значения разных типов могут быть равными, другие значения считаются равными, только если относятся к одному типу.

Примеры

Равенство чисел

Пример 122. Исходный код
1 == 1.0
Пример 123. Результат
true

Неравенство чисел

Пример 124. Исходный код
2 * 2 != 5
Пример 125. Результат
true

Сравнение объектов

Пример 126. Исходный код
{"key1": "value1", "key2": "value2"} == {"key2": "value2", "key1": "value1"}
Пример 127. Результат
true

Сравнение пустых значений

Пример 128. Исходный код
null == null
Пример 129. Результат
true

Сравнение значений разных типов

Пример 130. Исходный код
2 == "2"
Пример 131. Результат
false

Сравнение порядка

Операторы сравнения >, <, >= и <= применимы только к числам, строкам и меткам времени.

При сравнении строк используется лексикографический порядок, где символы сравниваются последовательно, на основе их номеров в таблице Unicode.

При сравнении меток времени большими считаются метки более поздней даты.

Примеры

Больше или равно

Пример 132. Исходный код
2 >= 2.0
Пример 133. Результат
true

Больше

Пример 134. Исходный код
2 > 1
Пример 135. Результат
true

Меньше или равно

Пример 136. Исходный код
2.0 <= 2
Пример 137. Результат
true

Меньше

Пример 138. Исходный код
1 < 2
Пример 139. Результат
true

Сравнение временных меток

Пример 140. Исходный код
t'2024-04-04T22:22:22.234142+01:00' > t'2024-04-04T22:22:22.234142+04:00'
Пример 141. Результат
true

Сравнение строк

Пример 142. Исходный код
"ё" > "я"
Пример 143. Результат
true

Логическое выражение

Выражение логического типа сравнивает два выражения (операнды), прекращая вычисление на последнем выражении, вычисленном в соответствии с оператором.

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

Синтаксис

Пример 144. Унарные операции
operator ~ expression
Пример 145. Бинарные операции
expression ~ operator ~ expression
Элемент Описание

expression

Операнд может быть любым выражением, которое возвращает допустимый тип, определенный оператором.

operator

Оператор определяет операцию, выполняемую над операндами:

  • && — конъюнкция (AND);

  • || — дизъюнкция (OR);

  • ! — отрицание (NOT).

Примеры

AND

Пример 146. Исходный код
true && true
Пример 147. Результат
true

OR с логическим значением

Пример 148. Исходный код
false || "foo"
Пример 149. Результат
foo

OR с пустым значением

Пример 150. Исходный код
null || "foo"
Пример 151. Результат
foo

NOT

Пример 152. Исходный код
!false
Пример 153. Результат
true

Вызов функции

Выражение вызова функции вызывает встроенные функции VRL.

Синтаксис

function ~ abort? ~ "(" ~ arguments? ~ ")" ~ closure?
Элемент синтаксиса Значение

function

Имя встроенной функции.

abort

Прерывание — литерал !, который можно использовать с функциями, возвращающими ошибки, для прерывания программы, если функция возвращает ошибку:

result = f!()

В противном случае ошибки должны обрабатываться:

result, err = f()

Отсутствие обработки ошибок от функций, которые могут возвращать ошибку, приводит к ошибкам на этапе компиляции. Смотрите Справочник ошибок VRL для дополнительной информации.

arguments

Выражения, разделенные запятыми, которые могут дополнительно предваряться документированным именем.

closure

Замыкание — необязательный фрагмент кода, разрешенный вызовом функции. Замыкание применяется преимущественно в функциях, выполняющих итерации по коллекциям. Пример синтаксиса:

for_each([]) -> |index, value| {
...
}

Примеры

Позиционный вызов функции

Пример 154. Исходный код
split("hello, world!", ", ")
Пример 155. Результат
[
"hello",
"world!"
]

Вызов функции с упорядоченными именованными аргументами

Пример 156. Исходный код
split("hello, world!", pattern: ", ")
Пример 157. Результат
[
  "hello",
  "world!"
]

Вызов функции с неупорядоченными именованными аргументами

Пример 158. Исходный код
split(pattern: ", ", value: "hello, world!")
Пример 159. Результат
[
  "hello",
  "world!"
]

Объединение

Выражение объединения состоит из нескольких выражений (операндов), разделенных оператором объединения ??. Логика объединения позволяет выбирать из списка выражений первое значение, которое соответствует заданному условию.

Оператор ?? полезен при обработке ошибок, так как позволяет задавать альтернативные способы обработки данных.

Синтаксис

expression ~ (operator ~ expression)+
Элемент Описание

expression

Операнд может быть любым выражением.

operator

Оператор разделяет два или более выражения.

Примеры

Объединение при ошибках

Пример 160. Исходный код
parse_syslog("не Syslog") ?? parse_common_log("не Common Log Format") ?? "malformed"
Пример 161. Результат
malformed

Условие (If)

Выражение условия определяет условное выполнение двух ветвей в зависимости от значения логического выражения. Если логическое выражение оценивается как истинное (true), выполняется ветвь "if". В противном случае выполняется ветвь "else", если она присутствует.

Синтаксис

"if" ~ predicate ~ block ~ ("else if" ~ predicate ~ block)* ~ ("else" ~ block)?
Элемент Описание

predicate

Предикат должен быть выражением, которое приводится к значению логического типа. Если логическое значение не возвращается, возникает ошибка на этапе компиляции. Предикат может содержать несколько выражений. Несколько предикатов выражений должны быть заключены в скобки. Выражения должны быть разделены точкой с запятой (;) или новой строкой.

Примеры

Условие if true

Пример 162. Исходный код
if true {
  "Hello, World!"
}
Пример 163. Результат
Hello, World!

Условие if false

Пример 164. Исходный код
if false {
  # Не вычисляется.
  null
}
Пример 165. Результат
null

Условие if/else

Пример 166. Исходный код
if false {
  # Не вычисляется.
  null
} else {
  "Hello, World!"
}
Пример 167. Результат
Hello, World!

Условие if … else if … else

Пример 168. Исходный код
if false {
  # Не вычисляется.
  null
} else if false {
  # Не вычисляется.
  null
} else {
  "Hello, World!"
}
Пример 169. Результат
Hello, World!

Многострочное выражение

Пример 170. Исходный код
x = 3
if (x = x + 1; x == 5) {
# not evaluated
  null
} else if (
  x = x + 1
  x == 5
) {
  "Hello, World!"
}
Пример 171. Результат
Hello, World!

Блок

Выражение блока представляет собой последовательность одного или нескольких выражений, заключенных в фигурные скобки.

Блоки не могут быть пустыми. Сочетание фигурных скобок без содержимого ({}) рассматривается как пустой объект.

Синтаксис

"{" ~ "NEWLINE"* ~ expressions ~ "NEWLINE"* ~ "}"
Элемент Описание

function

Имя встроенной функции.

expressions

Одно или несколько выражений.

Примеры

Простой блок

Пример 172. Исходный код
{
  message = "{\"Hello\": \"World!\"}"
  parse_json!(message)
}
Пример 173. Результат
{
  "Hello": "World!"
}

Присваивание результата блока

Пример 174. Исходный код
.structured = {
  message = "{\"Hello\": \"World!\"}"
  parse_json!(message)
}

Прерывание

Выражение abort приводит к завершению программы VRL, прерывая любые изменения, вносимые в событие.

Синтаксис

abort ~ message?
Элемент Описание

message

Необязательное отладочное сообщение, которое может быть использовано в диагностических целях и включается в метаданные события, отброшенного при преобразовании remap.

Примеры

Игнорирование недопустимых событий

Пример 175. Событие Vector
{
  "message": "hello world"
}
Пример 176. Исходный код
if contains(string!(.message), "hello") {
  abort
}
.message = "not hello world"
Пример 177. Результат
{
  "message": "hello world"
}