2010-10-18 5 views
8

J'ai un projet C# que j'ai l'intention de porter vers Objective-C. D'après ce que je comprends d'Obj-C, il semble qu'il existe une variété confuse d'options Regex mais je ne vois rien à propos d'une façon de faire un remplacement par un rappel.Existe-t-il une regex Objective-c remplacée par l'équivalent callback/C# MatchEvaluator?

Je cherche quelque chose qui est l'équivalent du délégué C# MatchEvaluator ou du preg_replace_callback de PHP. Un exemple de ce que je veux faire en C# est -

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

Comment pourrais-je faire en Objective-C? Dans ma situation actuelle, le Regex a à la fois des assertions de lookahead et de lookbehind, donc toute alternative impliquant de trouver les cordes à l'avance et ensuite de faire une série de remplacements de cordes droites ne fonctionnera malheureusement pas.

Répondre

7

Foundation a une classe NSRegularExpression (iOS4 et versions ultérieures) qui peut vous être utile. A partir de la documentation:

La méthode de correspondance fondamentale pour NSRegularExpression est un bloc méthode iterator qui permet aux clients de fournir un objet bloc qui sera appelé à chaque fois correspond à l'expression la régulière une partie de la cible chaîne. Il y a méthodes supplémentaires pour renvoyer tous les les allumettes dans un tableau, le total nombre de correspondances, le premier match, et la gamme du premier match.

Par exemple:

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

J'ai modifié le code de atshum pour le rendre un peu plus souple:

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

semble fonctionner pour l'instant (probablement besoin d'un peu plus de tests)

Questions connexes