Для разбора строки по шаблону есть четыре функции: 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