2010-12-17 11 views
4

テンプレートの代わりにブロックを取るNSRegularExpressionの– stringByReplacingMatchesInString:options:range:withTemplate:メソッドのバリエーションが必要でした。ブロックの戻り値は置換値として使用されます。あなたが想像できるように、これはテンプレートより柔軟です。 Perlの正規表現で/e修飾子を使用するような並べ替えをします。これは正常なObjective-Cブロックの実装ですか?

そこで、メソッドを追加するカテゴリを作成しました。これは、それは少し奇妙な感じのObjective Cのブロックと遊ぶのが私の最初の試みであるが、うまく動作しているようです

@implementation NSRegularExpression (Block) 

- (NSString *)stringByReplacingMatchesInString:(NSString *)string 
             options:(NSMatchingOptions)options 
             range:(NSRange)range 
            usingBlock:(NSString* (^)(NSTextCheckingResult *result))block 
{ 
    NSMutableString *ret = [NSMutableString string]; 
    NSUInteger pos = 0; 

    for (NSTextCheckingResult *res in [self matchesInString:string options:options range:range]) { 
     if (res.range.location > pos) { 
      [ret appendString:[string substringWithRange:NSMakeRange(pos, res.range.location - pos)]]; 
     } 
     pos = res.range.location + res.range.length; 
     [ret appendString:block(res)]; 
    } 
    if (string.length > pos) { 
     [ret appendString:[string substringFromIndex:pos]]; 
    } 
    return ret; 
} 

@end 

:これは私が思いついたものです。しかし、私はそれについてのいくつかの質問があります:

  1. これは、このような方法を実装するための純粋な方法のようですか?
  2. -enumerateMatchesInString:options:range:usingBlock: を使って内部構造を実装する方法はありますか?私はそれを試しましたが、ブロック内からposに割り当てることができませんでした。しかし、それを動作させる方法があれば、NSMatchingFlagsとBOOLを渡して、そのメソッドと同じ方法でそれらを処理することは賢明でしょう。できますか?

更新

デイブ・デロングからの回答のおかげで、私はブロックを使用して新しいバージョンを持っている:

@implementation NSRegularExpression (Block) 

- (NSString *)stringByReplacingMatchesInString:(NSString *)string 
             options:(NSMatchingOptions)options 
             range:(NSRange)range 
            usingBlock:(NSString * (^)(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop))block 
{ 
    NSMutableString *ret = [NSMutableString string]; 
    __block NSUInteger pos = 0; 

    [self enumerateMatchesInString:string options:options range:range usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop) 
    { 
     if (match.range.location > pos) { 
      [ret appendString:[string substringWithRange:NSMakeRange(pos, match.range.location - pos)]]; 
     } 
     pos = match.range.location + match.range.length; 
     [ret appendString:block(match, flags, stop)]; 
    }]; 
    if (string.length > pos) { 
     [ret appendString:[string substringFromIndex:pos]]; 
    } 
    return [NSString stringWithString:ret]; 
} 

@end 
素晴らしい作品

、ありがとう!

+0

これは本当に便利です。ありがとうございました! –

答えて

6

から宣言を変えるのと同じくらい簡単になりブロック内からposに割り当てることができること:

NSUInteger pos = 0; 

へ:

__block NSUInteger pos = 0; 
__blockキーワードの

詳細情報:__block Variables

+2

完璧に合理的で「デイブが言ったこと」。 :) – bbum

+0

恐ろしい、ありがとう!ブロックを使って質問を新しいバージョンに更新します。 – theory

関連する問題