Перебор совпадений
match находит только первое совпадение. Чтобы пройти по всем, используйте gmatch (g — от global, «везде») в цикле for, как вы используете ipairs. На каждом проходе цикла вы получаете следующую часть строки, подходящую под шаблон:
local eggs = "Eggs this week: 12 9 14 11"
local total = 0
for number in eggs:gmatch("%d+") do
total = total + tonumber(number)
end
print("Total: " .. total)Он выводит:
Total: 46Если в шаблоне есть захваты, у цикла есть переменная для каждого из них:
local stock = "carrots=24,potatoes=8,pumpkins=3"
for name, count in stock:gmatch("(%a+)=(%d+)") do
print(name .. ": " .. count)
endОн выводит:
carrots: 24
potatoes: 8
pumpkins: 3Сам gmatch не возвращает совпадения, а возвращает функцию, которую цикл for вызывает за следующим совпадением. Поэтому он имеет смысл только в цикле: print(stock:gmatch("%d+")) выведет лишь function: 0x…, адрес этой функции.
Здесь пригодятся ещё два элемента шаблонов. Набор в квадратных скобках обозначает один символ из списка: [aeiou] — гласная, [%d.] — цифра или точка (классы внутри набора тоже работают). С ^ в начале набор означает противоположное: [^,] — любой символ, кроме запятой. Поэтому [^,]+ — это «всё до следующей запятой», обычный способ разбить список значений:
local crops = "carrots,potatoes,пюре из тыквы"
for crop in crops:gmatch("[^,]+") do
print(crop)
endОн выводит:
carrots
potatoes
пюре из тыквыВ отличие от %a+, набору не мешают ни пробел, ни русские буквы в «пюре из тыквы». Посмотрите, что делает %a+ с русскими буквами в таком списке. Ошибки не будет, запись просто пропадёт:
local stock = "carrots=24,огурцы=5"
for name, count in stock:gmatch("(%a+)=(%d+)") do
print(name .. ": " .. count)
endОн выводит:
carrots: 24Ни одна буква слова огурцы не подходит под %a+, поэтому перед = шаблону нечего захватывать, и запись пропадает без всякого предупреждения.
И последний знак повторения: -, ноль или больше, но как можно меньше. .* берёт всё, что может, а .- останавливается, как только остальная часть шаблона подходит. Разницу видно на тексте между двумя метками:
local text = "Hugo (trader) and Joe (neighbor)"
print(text:match("%((.*)%)"))
for role in text:gmatch("%((.-)%)") do
print(role)
endОн выводит:
trader) and Joe (neighbor
trader
neighbor%( и %) — это скобки в самом тексте, а скобки без % — захват. С .* захват тянется от первой открывающей скобки до последней закрывающей; с .- — только до ближайшей.
Задание
- 1
Пройдите по заказу с помощью
gmatchи выведите каждую позицию на отдельной строке. Для названия используйте набор символов, чтобы словоогурцыне стало проблемой:carrots: 30 potatoes: 12 огурцы: 40 - 2
Найдите цену каждой позиции в
pricesи сложите, сколько платит Гуго: число штук, умноженное на цену, для каждой позиции. Под циклом выведитеГуго заплатит: 326 монет. (Ключ["огурцы"]стоит в квадратных скобках, потому что имя с русскими буквами нельзя написать без кавычек.)