2010-10-18 11 views
8

Ich habe ein C# -Projekt, das ich nach Objective-C portieren möchte. Von dem, was ich über Obj-C verstehe, sieht es so aus, als gäbe es eine verwirrende Vielfalt von Regex-Optionen, aber ich sehe nichts über eine Art, eine Ersetzung mit Callback durchzuführen.Gibt es einen Objective-C Regex ersetzen mit Callback/C# MatchEvaluator entspricht?

Ich bin auf der Suche nach etwas, das dem C# MatchEvaluator-Delegaten oder PHP-Preg_replace_callback entspricht. Ein Beispiel für das, was ich in C# machen möchte, ist -

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

Wie könnte ich das in Objective-C tun? In meiner aktuellen Situation hat der Regex jedoch sowohl Lookahead- als auch Lookbehind-Assertionen, so dass jede Alternative, die das Auffinden der Saiten im Voraus und das anschließende Ausführen einer Reihe von String-Ersetzungen betrifft, leider nicht funktioniert.

Antwort

7

Foundation hat eine NSRegularExpression Klasse (iOS4 und höher), die für Sie nützlich sein kann. Aus der Dokumentation:

Die grundlegenden Anpassungsverfahren für NSRegularExpression ist ein Block Iteratormethode, die Clients zu liefert ein Block-Objekt ermöglicht, die jedes Mal sein werden, der regelmäßige Ausdruck aufgerufen, um einen Teil der Zielspiele Zeichenfolge. Es gibt zusätzliche Convenience-Methoden für die Rückgabe aller die Übereinstimmungen als ein Array, die Summe Anzahl der Übereinstimmungen, die erste Übereinstimmung, und der Bereich der ersten Übereinstimmung.

Zum Beispiel:

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 atshum Code modifiziert es flexibler etwas zu machen:

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

scheint jetzt zu arbeiten (wahrscheinlich ein wenig mehr Tests benötigt)