2010-10-18 6 views
8

Mam projekt C# Mam zamiar przenieść do Objective-C. Z tego, co rozumiem w przypadku Obj-C, wygląda na to, że istnieje wiele różnych opcji Regex, ale nie widzę nic o sposobie zastąpienia wywołaniem zwrotnym.Czy istnieje Objective-c regex replace z odpowiednikiem callback/C# MatchEvaluator?

Szukam czegoś, co jest odpowiednikiem delegata C# MatchEvaluator lub preg_replace_callback w PHP. Przykładem tego, co chcę zrobić w języku C# jest -

// 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 ?' 

Jak mogę to zrobić w Objective-C? W mojej faktycznej sytuacji Regex ma w sobie zarówno twierdzenia z wyprzedzeniem, jak i lookbehind, więc każda alternatywa polegająca na wyszukiwaniu ciągów z wyprzedzeniem, a następnie robieniu serii prostych zastępów smyczków, nie będzie działać niestety.

Odpowiedz

7

Fundacja ma klasę NSRegularExpression (iOS4 i nowsze), które mogą Ci się przydać. Od docs:

Podstawową metodą dopasowywania do NSRegularExpression jest blok Metoda iterator, który pozwala klientom dostarczyć przedmiot grupowych, które będą wywoływany za każdym razem, gdy regularne wyrażenie pasuje część tarczy strunowy. Istnieją dodatkowe metody wygodnego zwracania wszystkich dopasowań jako tablicy, łącznej liczby meczów , pierwszego dopasowania, i zakresu pierwszego dopasowania.

Na przykład:

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

I zmodyfikowanego kodu atshum by uczynić go nieco bardziej elastyczne:

__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]]; 

wydaje się działać na teraz (prawdopodobnie wymaga trochę więcej badań)

Powiązane problemy