Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Challenge: String pattern for getting numbers from a string?

I've seen this question asked before where people want to get numbers from a string, and this is usually the answer:

text = "12..34abcd1.234abcd"
numbers = {}

for i = 1, string.len(text) do
	local pointer = string.sub(text, i, i)

	if tonumber(pointer) then
		table.insert(numbers, tonumber(pointer))
	end
end
print("{"..table.concat(numbers, ", ").."}")

...or something like that. That gives me each digit in the string. I want to get actual numbers from the string. I don't want {1, 2, 3, 4, 1, 2, 3, 4}, I want {12, 34, 1.234}. So, this is what I have:

pattern = "%d+%.*%d*"
text = "12..34abcd1.234abcd"
numbers = {}

for number in string.gmatch(text, pattern) do
	if tonumber(number) then
		table.insert(numbers, tonumber(number))
	end
end

print("{"..table.concat(numbers, ", ").."}")

...and that gives me exactly what I want. However, I want a little challenge. The pattern checks for arbitrary amounts of decimals. "3..........5" would be matched, but that's not a number. That's why I added the check on line 6. How can I remove the check on line 6 and still be guaranteed that each match in any string can be a number?

5 comments

0

Why would you even need that check on line 6 if you know what's going to be matched will be a digit?

0

I'm not looking for digits, I'm looking for numbers. 645, 1028, 1337, 3.1415, etc. If "3...5" was in the string and the check wasn't there, the script would put "3...5" in the table of numbers.

0

Still, why would you even need the check if what's going to be matched will be a number as stated in your string pattern?

0

The pattern checks for an arbitrary amount of decimals. "3.........5" would be matched, but that's not a number.

0

Ah, I see.

1 answer

✓ Accepted answer

Essentially, what you're saying is that the part after the decimal should be optional.

  • *: zero or more
  • +: one or more:
  • ?: zero or one -- This is the one we are interested in!

Consider this JavaScript regexp (\ replaces %):

\d+(\.\d*)?

The () "group" \.\d*. The ? makes the thing before optional (zero or one). We just make the decimal point followed by numbers optional!

Lua supports ?, but does not support grouping in conjunction with any other operators, so while most regular-expression systems let us do this, Lua does not.[^1]

[^1]: Lua does not implement regular expressions. Both because it does not support all features of regular languages (like using ? and * with groups) and because it supports non regular features (%b)

In this case, it so happens that's not a problem. The key here is that what is before and after the %. is the same -- it's %d repeated a bunch. So this will be what we want:

%d+%.?%d*

Broken apart: %d+ %.? %d*

What does this accept?

  • 10 . 5
  • 10 .
  • 1
  • 1 2
  • 12
  • 12 (It doesn't really matter which one)

Note that this does not accept .25, because you used + on the first (though that's probably OK). You have to use either + before or after, or else . will be a valid number.


Note: tonumber allows a bunch of other formats for numbers, so while everything %d+%.?%d accepts will be a number, not all valid inputs to tonumber will be matched by this pattern.

This discussion is preserved as it was. New answers, comments, and votes are closed.