Looping over Matches
match finds only the first match. To go through all of them, use gmatch (the g stands for global, everywhere) in a for loop, the way you use ipairs. Each pass of the loop gets the next part of the text that fits the pattern:
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)This prints:
Total: 46When the pattern has captures, the loop has a variable for each of them:
local stock = "carrots=24,potatoes=8,pumpkins=3"
for name, count in stock:gmatch("(%a+)=(%d+)") do
print(name .. ": " .. count)
endThis prints:
carrots: 24
potatoes: 8
pumpkins: 3gmatch itself doesn't give the matches; it gives a function, which the for loop calls for the next match. So it only makes sense in a loop: print(stock:gmatch("%d+")) prints just function: 0x…, the address of that function.
Two more pieces of patterns come in handy here. A set in square brackets stands for one character from a list: [aeiou] is a vowel, [%d.] a digit or a period (classes work inside a set too). With ^ at its start, a set means the opposite: [^,] is any character except a comma. So [^,]+ is “everything up to the next comma”, the usual way to split a list of values:
local crops = "carrots,potatoes,pumpkin purée"
for crop in crops:gmatch("[^,]+") do
print(crop)
endThis prints:
carrots
potatoes
pumpkin puréeUnlike %a+, the set has no problem with the space or the accent in “pumpkin purée”. Look what %a+ does with an accent in such a list. It doesn't end with an error; it quietly finds something else:
local stock = "carrots=24,jalapeños=5"
for name, count in stock:gmatch("(%a+)=(%d+)") do
print(name .. ": " .. count)
endThis prints:
carrots: 24
os: 5The letters before the ñ can't reach the =, so the pattern took the letters after it, os, and nothing warns you.
And the last sign for repeating: -, zero or more, but as few as possible. .* takes all it can, .- stops as soon as the rest of the pattern fits. You see the difference with a text between two marks:
local text = "Hugo (trader) and Joe (neighbor)"
print(text:match("%((.*)%)"))
for role in text:gmatch("%((.-)%)") do
print(role)
endThis prints:
trader) and Joe (neighbor
trader
neighbor%( and %) are the parentheses in the text, and the parentheses without % are the capture. With .*, the capture runs from the first opening parenthesis to the last closing one; with .-, only to the nearest one.
Instructions
Go through the order with gmatch and print each item on a line of its own. For the name, use a set, so that the ñ isn't a problem:
carrots: 30
potatoes: 12
jalapeños: 40Look up the price of each item in prices and add up how much Hugo pays: the number of pieces times the price, for every item. Below the loop, print Hugo pays 326 coins. (The key ["jalapeños"] is in square brackets because a name with an accent can't be written without quotes.)
Start programming for free
7/9