Reputation: 2186
I use NSRegularExpression to find matched by a certain patter, which is visible in the snippet:
- (NSString *)functionPattern
{
return @"[A-Za-z]{1,}\\([A-Za-z0-9,\\(\\)]{1,}\\)";
}
- (void)test
{
NSString *formula = @"AVERAGE(G17,G18,AVERAGE(G20,G21,MIN(G30,G31)))";
NSError *error;
NSRegularExpression *functionRegex = [NSRegularExpression regularExpressionWithPattern:[self functionPattern]
options:NSRegularExpressionCaseInsensitive
error:&error];
if (error) {
NSLog(@"error");
return;
}
NSArray *matches = [functionRegex matchesInString:formula options:0 range:NSMakeRange(0, formula.length)];
for (NSUInteger i = 0; i < matches.count; i++) {
NSTextCheckingResult *result = matches[i];
NSString *match = [formula substringWithRange:result.range];
NSLog(@"%@", match);
}
}
My natural expectation was to get 3 matches: AVERAGE(...), AERAGE(...) and MIN(...). Surprisingly for me, i only get one match: AVERAGE(G17,G18,AVERAGE(G20,G21,MIN(G30,G31)))
.
If the formula is AVERAGE(G17,G18)+AVERAGE(G20,G21,MIN(G30,G31))
, i'll get 2 matches: AVERAGE(G17,G18)
and AVERAGE(G20,G21,MIN(G30,G31))
. In other words, after a match is found, a search for the pattern is not performed in the range of the matched string.
Please advice how to overcome this, and find all possible matches. Am i missing something simple here?
What i'm doing is parsing and evaluating math expressions. All works fine, except for the cases of nested functions. If i know all possible function names in advance, can that be utilised somehow?
I'm hoping to fine more or less elegant approach; if i can i'd like to avoid things like "stripping off function name and parentheses'"
Help is much appreciated.
Upvotes: 0
Views: 549
Reputation: 53000
You cannot do what you want, at least the way you want to.
Regular expressions are technically a type 3 grammar and cannot describe recursive languages; your math expressions can contain other math expressions.
You could do something along the line of what you say you don't want to do. For example you could match an expression containing just a single pair of balanced parentheses, so in AVERAGE(G20,G21,MIN(G30,G31))
you could match MIN(G30,G31)
. If you then replaced the match by a marker and matched again you could match the next level, etc. But this not a good way to do it.
General math expressions can be described by a type 2 grammar, and can be easily parsed using a recursive descent parser. Such parsers are very easy to write. Essentially you write down the grammar you wish to parse and then write a function for each production. Google will get you started down this route.
If you don't want to write the parser yourself you can use a parser generator, in which case you still need to write the grammar, or search for one of the math expression libraries.
HTH
Upvotes: 1