Шаблоны
С помощью find и 1, true вы ищете точный текст. Но часто вы не знаете сам текст, а только его вид: «число», «слово после Sold». Для этого в Lua есть шаблоны: строки, в которых некоторые символы имеют особый смысл. (Во многих языках для этого есть регулярные выражения. Шаблоны Lua — их более маленький и простой родственник: если вы знаете регулярные выражения, не ищите здесь | и \d.)
Метод match возвращает первую часть строки, подходящую под шаблон, или nil, если ничего не подошло. Самые полезные элементы шаблона — классы символов, каждый из которых обозначает один символ определённого вида:
%d: цифра от 0 до 9;%a: буква от a до z, строчная или заглавная;%w: буква или цифра;%s: пробел (или табуляция, или перевод строки);.: любой символ.
Заглавная буква означает противоположное: %D — любой символ, кроме цифры, %S — любой символ, кроме пробела. После класса указывают, сколько таких символов нужно: + — один или больше, сколько возможно; * — ноль или больше, сколько возможно. Без них класс означает ровно один символ:
local note = "The hens laid 18 eggs"
print(note:match("%d+"))
print(note:match("%a+"))
print(note:match("%d"))
print(note:match("%d+%s*%a+"))Он выводит:
18
The
1
18 eggsПоследний шаблон читается так: «цифры, возможно пробелы, буквы». Знак * после %s допускает и полное отсутствие пробела, поэтому шаблон нашёл бы и 18eggs.
Два символа привязывают шаблон к краям строки: ^ в начале шаблона означает, что совпадение должно начинаться с начала строки, а $ в конце шаблона — что оно должно заканчиваться в конце строки. С обоими подойти должна вся строка целиком. Так проверяют, что строка — целое число:
print(("42"):match("^%d+$"))
print(("42 eggs"):match("^%d+$"))Он выводит:
42
nilЧаще всего нужна не вся совпавшая часть, а несколько её кусков. Возьмите эти части шаблона в круглые скобки, получатся захваты, и match вернёт только их, по одному значению на каждую пару скобок:
local entry = "Sold 24 eggs"
local count, item = entry:match("Sold (%d+) (%a+)")
print(item, count)
print(tonumber(count) * 2)Он выводит:
eggs 24
48Части вне скобок, Sold и пробелы, тоже должны быть в строке, но не возвращаются. Захваты — всегда строки, даже "24", поэтому превращайте их в числа с помощью tonumber. А если строка не подходит под шаблон, match возвращает просто nil, так что и count, и item равны nil: проверяйте их, прежде чем использовать.
Символы с особым смыслом, ( ) . % + - * ? [ ] ^ $, называют магическими символами. Чтобы найти такой символ как обычный, поставьте перед ним %: %. — это точка, %( — скобка:
print(("Price: 3.50 coins"):match("%d+%.%d+"))Он выводит:
3.50И снова про русские буквы. %a и %w знают только буквы от a до z, поэтому в русском слове они не находят ничего:
print(("огурцы"):match("%a+"))Он выводит:
nilДля слов, в которых могут быть русские буквы, используйте %S+: все символы до следующего пробела (и знаки препинания тоже, так что запятая сразу после слова станет частью захвата).
Задание
- 1
Замените
printв цикле: достаньте из каждой заметки число, культуру и монеты одним вызовомmatchс тремя захватами. Название культуры захватывайте с помощью%S+, потому что%a+не знает русских букв. Заметка про дождь не подходит под шаблон: пропустите её. Для каждой продажи выведите цену одной штуки (делите с помощью//, чтобы получилось целое число):12 тыкв, цена за штуку: 20 40 огурцов, цена за штуку: 2 - 2
Под циклом выведите, сколько монет Эмма получила со всех продаж вместе:
Всего монет: 320.