2010-10-18 4 views
8

У меня есть проект C#, который я намерен передать в Objective-C. Из того, что я понимаю об Obj-C, похоже, что существует множество запущенных вариантов Regex, но я ничего не вижу о способе замены с помощью обратного вызова.Есть ли регулярное выражение Objective-c с эквивалентом обратного вызова/C# MatchEvaluator?

Я ищу что-то, что является эквивалентом делегата C# MatchEvaluator или preg_replace_callback PHP. Пример того, что я хочу сделать в C# есть -

// change input so each word is followed a number showing how many letters it has 

string inputString = "Hello, how are you today ?"; 
Regex theRegex = new Regex(@"\w+"); 

string outputString = theRegex.Replace(inputString, delegate (Match thisMatch){ 
    return thisMatch.Value + thisMatch.Value.Length; 
}); 

// outputString is now 'Hello5, how3 are3 you3 today5 ?' 

Как я мог бы сделать это в Objective-C? В моей реальной ситуации Regex имеет как взгляды, так и взгляды в нем, хотя любая альтернатива, связанная с поиском строк заранее, а затем с выполнением серии прямых замеров строк, не будет работать, к сожалению.

ответ

7

Фонд имеет класс NSRegularExpression (iOS4 и более поздние версии), который может пригодиться вам. Из документов:

Основного метод согласования для NSRegularExpression является метод итератора Блока , который позволяет клиентам поставить объект блока, который будет вызывается каждый раз, когда регулярное выражения соответствует части мишени строка. Есть дополнительные методы удобства для возврата всех совпадений в виде массива, всего кол-во матчей, первого совпадения, и диапазона первого совпадения.

Например:

NSString *input = @"Hello, how are you today?"; 

// make a copy of the input string. we are going to edit this one as we iterate 
NSMutableString *output = [NSMutableString stringWithString:input]; 

NSError *error = NULL; 
NSRegularExpression *regex = [NSRegularExpression 
           regularExpressionWithPattern:@"\\w+" 
                options:NSRegularExpressionCaseInsensitive 
                 error:&error]; 

// keep track of how many additional characters we've added (1 per iteration) 
__block NSUInteger count = 0; 

[regex enumerateMatchesInString:input 
         options:0 
          range:NSMakeRange(0, [input length]) 
        usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){ 

    // Note that Blocks in Objective C are basically closures 
    // so they will keep a constant copy of variables that were in scope 
    // when the block was declared 
    // unless you prefix the variable with the __block qualifier 

    // match.range is a C struct 
    // match.range.location is the character offset of the match 
    // match.range.length is the length of the match   

    NSString *matchedword = [input substringWithRange:match.range]; 

    // the matched word with the length appended 
    NSString *new = [matchedword stringByAppendingFormat:@"%d", [matchedword length]]; 

    // every iteration, the output string is getting longer 
    // so we need to adjust the range that we are editing 
    NSRange newrange = NSMakeRange(match.range.location+count, match.range.length); 
    [output replaceCharactersInRange:newrange withString:new]; 

    count++; 
}]; 
NSLog(@"%@", output); //output: Hello5, how3 are3 you3 today5? 
3

Я модифицированном код atshum, чтобы сделать его немного более гибким:

__block int prevEndPosition = 0; 
[regex enumerateMatchesInString:text 
         options:0 
          range:NSMakeRange(0, [text length]) 
        usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop) 
{ 
    NSRange r = {.location = prevEndPosition, .length = match.range.location - prevEndPosition}; 

    // Copy everything without modification between previous replacement and new one 
    [output appendString:[text substringWithRange:r]]; 
    // Append string to be replaced 
    [output appendString:@"REPLACED"]; 

    prevEndPosition = match.range.location + match.range.length; 
}]; 

// Finalize string end 
NSRange r = {.location = prevEndPosition, .length = [text length] - prevEndPosition}; 
[output appendString:[text substringWithRange:r]]; 

Кажется работать сейчас (вероятно, нужно немного больше тестирования)