Pedro Rolo
Pedro Rolo

Reputation: 29930

NSRegularExpression enumerateMatchesInString: [...] usingBlock does never stop

I am invoking the mentioned function and it is correctly iterating through all the matches. Though, it does not finish executing after all the matched blocks were handled. What might I be doing wrong?

The used regexp is: /\[([^\[\{,]*(,\n)?)*\]/

Upvotes: 1

Views: 3605

Answers (2)

Rob
Rob

Reputation: 437432

Judging from your answer to your own question, it appears that you solved the problem by passing NSMatchingReportCompletion. I suspect that you may have cured a symptom rather than the disease.

I wonder if you may have accidentally passed the wrong options value to enumerateMatchesInString. For example, it's very easy to mistakenly invoke it like so:

[regex enumerateMatchesInString:stringToSearch
                        options:NSRegularExpressionCaseInsensitive
                          range:NSMakeRange(0, [stringToSearch length])
                     usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
                         // This is called many times, 
                         // even when there is no match!
                     }];

This, at first blush, looks fine, the compiler doesn't complain, but we get the undesirable behavior of the block getting called too many times, often with result == nil.

You can solve this problem by adding NSMatchingReportCompletion to the options, and rather than getting the block called many times, it's called just for the matches and once more upon completion. That fixes it, but it's an inelegant solution and overlooks the source of the problem.

The issue is that NSRegularExpressionCaseInsensitive simply is not an appropriate value for the options parameter of enumerateMatchesInString ... it's an options value for regularExpressionWithPattern). Worse, NSRegularExpressionCaseInsensitive just happens to be identical to NSMatchingReportProgress, which generates the behavior you describe.

The correct solution is to simply pass an options value of 0, like below, and enumerateMatchesInString will be called just for matches, and not for interim progress and not upon completion:

[regex enumerateMatchesInString:stringToSearch
                        options:0
                          range:NSMakeRange(0, [stringToSearch length])
                     usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
                         // do stuff here
                     }];

Upvotes: 4

Pedro Rolo
Pedro Rolo

Reputation: 29930

I have fixed this issue by passing NSMatchingReportCompletion as option and by setting stop to YES when the match is nil.

Upvotes: 0

Related Questions