2010-10-18 12 views
8

Ho un progetto C# che intendo portare su Objective-C. Da quanto ho capito su Obj-C, sembra che ci sia una varietà confusionaria di opzioni Regex, ma non riesco a vedere nulla su un modo di fare una sostituzione con callback.Esiste una regex Objective sostituita con callback/C# equivalente MatchEvaluator?

Sto cercando qualcosa che sia l'equivalente del delegato di C# MatchEvaluator o del preg_replace_callback di PHP. Un esempio di quello che voglio fare in 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 ?' 

Come potrei fare questo in Objective-C? Nella mia situazione attuale, il Regex ha comunque un aspetto in testa e guarda dietro le affermazioni, quindi qualsiasi alternativa che preveda di trovare le stringhe in anticipo e quindi di eseguire una serie di sostituzioni di stringhe diritte non funzionerà purtroppo.

risposta

7

Foundation ha una classe NSRegularExpression (iOS4 e successive), che potrebbe essere utile. Dalla documentazione:

Il metodo di corrispondenza fondamentale per NSRegularExpression è un metodo iteratore Block che permette ai clienti di fornire un oggetto blocco che sarà richiamato ogni volta che il regolare espressione corrisponde una porzione del bersaglio stringa. Esistono altri metodi di convenienza per restituire tutte le partite come una matrice, il numero totale di corrispondenze, la prima partita, e l'intervallo della prima corrispondenza.

Ad esempio:

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

Ho modificato il codice di atshum per renderlo un po 'più flessibile:

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

sembra funzionare per ora (probabilmente ha bisogno di un altro test bit)

Problemi correlati