8

Objective-Cに移植する予定のC#プロジェクトがあります。Obj-Cについて私が理解していることから、紛らわしいさまざまな正規表現オプションがあるように見えますが、コールバックで置換を行う方法については何もわかりません。

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でこれを行うにはどうすればよいですか?私の実際の状況では、正規表現には先読みアサーションと後読みアサーションの両方が含まれているため、事前に文字列を見つけてから一連の文字列の置き換えを行うという代替手段は、残念ながら機能しません。

4

2 に答える 2

7

FoundationにはNSRegularExpressionクラス(iOS4以降)があり、これは便利な場合があります。ドキュメントから:

NSRegularExpressionの基本的なマッチングメソッドは、正規表現がターゲット文字列の一部と一致するたびに呼び出されるBlockオブジェクトをクライアントが提供できるようにするBlockイテレータメソッドです。すべての一致を配列、一致の総数、最初の一致、および最初の一致の範囲として返すための追加の便利なメソッドがあります。

例えば:

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?
于 2011-01-22T07:55:04.667 に答える
3

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

今のところ動作しているようです(おそらくもう少しテストが必要です)

于 2012-11-01T14:56:42.730 に答える