Есть ли в Objective-c регулярное выражение с обратным вызовом / C # MatchEvaluator? - PullRequest
8 голосов
/ 18 октября 2010

У меня есть проект на C #, который я собираюсь перенести на Objective-C.Из того, что я понимаю об Obj-C, похоже, что существует множество запутанных вариантов Regex, но я не вижу ничего о способе замены на callback.

Я ищу что-то, что эквивалентно делегату C # MatchEvaluator или PHP preg_replace_callback.Пример того, что я хочу сделать в 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 есть утверждения как прогнозирующие, так и прогнозируемые, поэтому любая альтернатива, включающая нахождение строк заранее и последующую серию прямых замен, к сожалению, работать не будет.

Ответы [ 2 ]

7 голосов
/ 22 января 2011

Foundation имеет класс 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 голосов
/ 01 ноября 2012

Я изменил код 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]];

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...