Шаблоны

Шаблоны

Для разбора строки по шаблону есть четыре функции: string.find, string.gsub, string.match и string.gmatch. Все они требуют, собственно, шаблон.

Шаблон — это строка, абстрактно описывающая содержимое других строк. Например, шаблон "%d" описывает любую строку, состояющую из одной цифры (то есть "0", "1", "2", "3", "4", "5", "6", "7", "8" и "9").

Шаблон является последовательностью элементов шаблона и захватов.

Самые простые элементы шаблона — это классы символов.

Класс символов Описание
x Если символ x не является одним из `^$()%.[]*+-?`, то представляет самого себя
. Любой символ
%a Все буквы латинского алфавита
%c Все управляющие символы (\x00\x1f и \x7f)
%d Все цифры
%g Все символы, которые можно вывести на экран, кроме пробела (т.е. у них есть глифы)
%l Все символы в нижнем регистре
%p Все символы пунктуации
%s Все пробельные символы
%u Все символы в верхнем регистре
%w Все цифры и буквы
%x Все шестнадцатеричные цифры
%char Символ char
[классы символов] Набор — представляет любой из составных классов. Можно использовать как обычные символы, так и %-классы. Чтобы включить в набор символ ], нужно указать его первым символом ([]+%wa-f]). Диапазон символов указывается нижней границей, символом - и верхней границей ([a-zA-Z]). Сам символ - можно добавить в набор указав последним или первым. Символ % нужно экранировать (%%).
[^классы символов] Инвертированный набор — все символы, кроме соответствующих перечисленным классам.

Если %-класс символов записать с большой буквой, то класс инвертируется. Например, %S — все символы, кроме пробельных.

Класс символов может быть составной частью элемента шаблона. Все элементы:

  • Просто класс символов. Соответствует одному символу из класса.
  • Класс символов и *. Соответствует нулю или более символов из класса. Жадное соответствие: пытается найти как можно больше символов, чтобы всё ещё соответствовать шаблону.
  • Класс символов и +. Соответствует одному и более символам из класса. Жадное соответствие.
  • Класс символов и -. Соответствует нулю или более символов из класса. В отличие от *, находит минимальное кол-во символов, чтобы соответствовало шаблону.
  • Класс символов и ?. Соответствует нулю или одному символу.
  • %n. Соответствует содержимому энного захвата.
  • %bxy. Для двух символов (не классов) x и y находит соответствие так, чтобы x и y были сбалансированы. Для символа x счётчик увеличивается на 1, для символа y — уменьшается на 1, в соответствии счётчик равен нулю. Полезно, чтобы искать сбалансированные скобки (%b()), например.
  • %f[набор]. Соответствует пустой строке такой позиции, что следующий символ соответствует набору, а предыдущий не соответствует. Конец и начало строки принимаются за нулевой байт \0.

Шаблон может начинаться с ^ — будет искаться соответствие с начала строки — или $ — тогда с конца. Если оба символа указать, то шаблон проверяться будет на всю строку.

Шаблон может содержать захваты — подшаблоны, значения которых возвращается. Они обозначаются круглыми скобками и нумеруются в порядке появления левых скобок. Например, в шаблоне ((..)((%d+)%s))%s первым будет (..)((%d+)%s), вторым — (..), третьим — (%d+)%s, четвёртым — %d+.

Если захват пустой, то вернётся число — текущая позиция матчера в строке.

Шаблоны можно скармливать в четыре функции стандартной либы string:

  • string.find(str: string, pattern: string[, init: number[, plain: boolean]]) — ищет в строке str первое совпадение шаблона pattern и возвращает индексы начала и конца. Если совпадения не найдено, вернёт nil. Захваты в шаблоне, если они есть, возвращаются после индексов.
  • string.match(str: string, pattern: string[, init: number]) — также ищет в строке str шаблон pattern. Возвращает захваты из первого совпадения или всё совпадение, если захватов нет.
  • string.gmatch(str: string, pattern: string) — то же, что и string.match, но возвращает итератор, который отдаёт каждое совпадение шаблона pattern в строке str. Итератор можно использовать в цикле for in.
  • string.gsub(str: string, pattern: string, repl[, n: number]) — заменяет в строке str совпадения шаблона pattern на значение, определяемое аргументом repl: если это строка, то на эту строку будет заменяться; если это таблица — на строку по ключу, соответствующую совпадению; если это функция — на возвращаемое значение функции.

Примеры

print(string.find("string 123", "(%d+)"))
--> 8       10      123

-- Парсить даты
print(string.match("2048-01-02 04:08:16",
                   "(%d%d%d%d)-(%d%d)-(%d%d) (%d%d):(%d%d):(%d%d)"))
--> 2048    01      02      04      08      16

-- Делить строку по разделителю (например, запятой)
for match in string.gmatch("item1, item2, item3, item4",
                           "%s*([^,]+)") do
  print(("%q"):format(match))
end
--> "item1"
--> "item2"
--> "item3"
--> "item4"

-- Убрать пробелы в начале и в конце строки
local s = "    test   test     "
print(("%q"):format((string.gsub(s, "^%s*(.-)%s*$", "%1"))))
--> "test   test"

-- Интерполяция по значениям из таблицы
print(string.gsub("${name}-${version}.tar.gz", "%${(.-)}", {
  name = "lua",
  version = "5.3"
}))
--> lua-5.3.tar.gz  2

num1 = 32
num2 = 128
-- Интерполяция результата выполнения произвольного кода
-- (локальные переменные не увидит)
print(string.gsub("${num1} * ${num2} = ${num1 * num2}", "%$(%b{})",
                  function(match)
                    -- `match` содержит знаки `{` и `}`, поэтому их обрезаем:
                    match = match:sub(2, -2)

                    -- Исполняем полученный код как выражение
                    local chunk = load("return " .. match, match, "t")

                    if not chunk then
                      return assert(load(match))()
                    else
                      return chunk()
                    end
                  end))
--> 32 * 128 = 4096 3

Подробнее

results for ""

    No results matching ""