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: 46

When 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)
end

This prints:

carrots: 24
potatoes: 8
pumpkins: 3

gmatch 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)
end

This prints:

carrots
potatoes
pumpkin purée

Unlike %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)
end

This prints:

carrots: 24
os: 5

The 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)
end

This 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: 40

Look 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

By signing up, you agree to the Terms of Service and Privacy Policy.

Or sign up with:

7/9