2015-10-13 3 views
1

Аналогичный вопрос: Recursive pattern in regex, но в Objective-c.Рекурсивный рисунок в NSRegularExpression

Я хочу найти диапазоны или подстроки внешних кронштейнов.

Пример ввода:

NSString *input = @"{a {b c}} {d e}"; 

Пример результата:

// yeah, I know, we can't put NSRange in an array, it is just to illustrate 
NSArray *matchesA = @[NSMakeRange(0, 9), NSMakeRange(10, 5)]; // OK 
NSArray *matchesB = @[NSMakeRange(1, 7), NSMakeRange(11, 3)]; // OK too 

NSArray *outputA = @[@"{a {b c}}", @"{d e}"]; // OK 
NSArray *outputB = @[@"a {b c}", @"d e"];  // OK too 

К сожалению, NSRegularExpression не принимает ?R, по-видимому. Любая альтернатива, соответствующая внешним скобкам?

+6

ICU регулярное выражение вкус не поддерживает рекурсию. Вам нужно будет разобрать строки «вручную». И FYI, вы, должно быть, имели в виду '(? R)', а не '\ R'. –

ответ

0

Идет для решения вручную.

Предполагая:

NSString *text = @"{a {b c}} {d e}"; 

красивое решение без регулярных выражений

NSUInteger len = text.length; 
unichar buffer[len + 1]; 
[text getCharacters:buffer range:NSMakeRange(0, len)]; 
NSMutableOrderedSet<NSValue *> *results = [NSMutableOrderedSet orderedSet]; 
NSInteger depth = 0; 
NSUInteger location = NSNotFound; 
for (NSUInteger i = 0; i < len; i++) { 
    if (buffer[i] == '{') 
    { 
     if (depth == 0) 
      location = i; 
     depth++; 
    } 
    else if (buffer[i] == '}') 
    { 
     depth--; 
     if (depth == 0) 
      [results addObject:[NSValue valueWithRange:NSMakeRange(location, i - location + 1)]]; 
    } 
} 

return results; 

некрасиво решение с регулярным выражением

NSString *innerPattern = @"\\{[^{}]*\\}"; 
NSRegularExpression *innerBracketsRegExp = [NSRegularExpression regularExpressionWithPattern:innerPattern options:0 error:nil]; 
// getting deepest matches 
NSArray<NSTextCheckingResult *> *deepestMatches = [innerBracketsRegExp matchesInString:text options:0 range:NSMakeRange(0, text.length)]; 
// stripping them from text 
text = [text stringByReplacingOccurrencesOfString:innerPattern withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, text.length)]; 
// getting new deepest matches 
NSArray<NSTextCheckingResult *> *depth2Matches = [innerBracketsRegExp matchesInString:text options:0 range:NSMakeRange(0, text.length)]; 

// merging the matches of different depth 
NSMutableOrderedSet<NSValue *> *results = [NSMutableOrderedSet orderedSet]; 
for (NSTextCheckingResult *cr in depth2Matches) { 
    [results addObject:[NSValue valueWithRange:cr.range]]; 
} 
for (NSTextCheckingResult *cr in deepestMatches) { 
    __block BOOL merged = NO; 
    [results enumerateObjectsUsingBlock:^(NSValue * _Nonnull value, NSUInteger idx, BOOL * _Nonnull stop) { 
     if (merged) 
      [results replaceObjectAtIndex:idx withObject:[NSValue valueWithRange:NSMakeRange(value.rangeValue.location + cr.range.length, value.rangeValue.length)]]; 
     else if (NSLocationInRange(cr.range.location, value.rangeValue)) 
     { 
      [results replaceObjectAtIndex:idx withObject:[NSValue valueWithRange:NSMakeRange(value.rangeValue.location, value.rangeValue.length + cr.range.length)]]; 
      merged = YES; 
     } 
     else if (cr.range.location < value.rangeValue.location) 
     { 
      [results insertObject:[NSValue valueWithRange:cr.range] atIndex:idx]; 
      merged = YES; 
     } 
    }]; 
    if (!merged) 
     [results addObject:[NSValue valueWithRange:cr.range]]; 
} 

return results;