# Question about a particular string pattern

I think I have some brushing up to do with string patterns.

Given an expression like `"5+2"`, I want to find a string pattern which will match that. The answer is `"%d+[%+%-%*%^/]%d+"`, (ignoring the multiple operators supported you can shorten this to `"%d+[%+%-%*]%d+"` just so it’s more readable and you can understand the problem). My problem is, if I had an expression with multiple operators and operands, like `"2+67*36"`, the pattern `"%d+[%+%-%*]%d+"` wouldn’t work, because it’s supposed to detect a single `operand operator operand` expression.

``````string.match("2+67*36", "%d+[%+%-%*]%d+") --2+67, and not 2+26*36
``````

My question is how would I make a pattern to detect an expression with multiple operations like in the example above. `"[%d%+%-%*%d]+"` is a solution, but that won’t take count of something like `"2++8*36"`, this is invalid, but the pattern above matches is it.

2 Likes

I don’t believe Lua’s string matching capabilities can solve this alone. Initially, my thought was to do something like `%d+[%+%-%*]%d+([%+%-%*]%d+)*`. In other words, match `number, operator, number`, and then optionally, more `operator, number` patterns (using parentheses notation, but that’s not a thing, sadly). Unfortunately, Lua’s patterns don’t let you repeat patterns/strings (only characters), which renders the matching additional `operator, number` patterns part impossible. The alternative I found was to manually get more `operator, number` patterns like so:

``````local function Match(String)
local Substring = ""
local Start, End = string.find(String, "%d+[%+%-%*]%d+")	--> find the initial number, operator, number pattern
if Start then
Substring = String:sub(Start, End)
while true do
Start, End = string.find(String, "^[%+%-%*]%d+", End + 1)	--> find additional operator, number patterns, ensuring that the patterns come one after the other
if Start then
Substring = Substring .. String:sub(Start, End)
else
break
end
end
return Substring
else
return nil
end
end

print(Match("2+67*36-45")) 	--> 2+67*36-45
print(Match("2++67*45++5")) --> 67*45
print(Match("2+67**45")) 	--> 2+67
print(Match("2"))			--> nil
print(Match("5+5+"))		--> 5+5``````

I’m not sure how you would like to handle weird string expressions (see the second and third examples in my code). The way I have it is that it’ll find any `number, operator, number` pattern and start looking for additional `operator, number` patterns from there (strictly making sure that these patterns come one after another, and stopping when this behavior is interrupted). This behavior can be modified to check that the initial `number, operator, number` must come first (and with additional end checks, you can make it so that only correct expressions are accepted). You can also modify the string patterns to accept negative numbers (`%-?` before the `%d+`).

Here’s an example that will only accept valid input (returns nil for invalid expressions):

``````local function StrictMatch(String)
local Substring = ""
local Start, End = string.find(String, "^%d+[%+%-%*]%d+")	--> find the initial number, operator, number pattern
if Start then
Substring = String:sub(Start, End)
while true do
if End == #String then
return Substring
end
Start, End = string.find(String, "^[%+%-%*]%d+", End + 1)	--> find additional operator, number patterns, ensuring that the patterns exist at the beginning
if Start then
Substring = Substring .. String:sub(Start, End)
else
return nil
end
end
return Substring
else
return nil
end
end

print(StrictMatch("2+67*36-45")) 	--> 2+67*36-45
print(StrictMatch("4+555"))			--> 4+555
print(StrictMatch("2++67*45++5")) 	--> nil
print(StrictMatch("2+67**45")) 		--> nil
print(StrictMatch("2"))				--> nil
print(StrictMatch("5+5+"))			--> nil``````

I’m curious to see if there’s a more elegant solution though! Hopefully I didn’t overlook anything.

3 Likes

Very sorry for the late response

Thanks a lot for taking your time to write this! Unfortunately you are correct. There is no way you can check for repeating patterns. Only way to do so is by doing what you did, or using `string.gmatch`. I think what I’m gonna end up doing is use the pattern `[%d%+%-%*%d]+` to check if a string has characters that form an expression, and then introduce a function to check if that expression is valid or not. Also, I’m actually doing this for a parser which is intended to be a challenge by someone. Which means I don’t really need to care about sanitizing input, I can just expect that the user would input valid code, and if not the code I wrote can error naturally by itself. Thanks!

1 Like