4

– stringByReplacingMatchesInString:options:range:withTemplate:テンプレートの代わりにブロックを取るNSRegularExpression のメソッドのバリエーションが必要でした。ブロックの戻り値が置換値として使用されます。ご想像のとおり、これはテンプレートよりも柔軟です。/ePerl 正規表現で修飾子を使用するようなものです。

そこで、メソッドを追加するカテゴリを作成しました。これは私が思いついたものです:

@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

Objective C でブロックを操作するのはこれが初めての試みです。少し奇妙に感じますが、うまく機能しているようです。ただし、それについていくつか質問があります。

  1. これは、そのようなメソッドを実装するための正気な方法のように思えますか?
  2. を使用して内部を実装する方法はあり-enumerateMatchesInString:options:range:usingBlock: ますか? posやってみたのですが、ブロック内から代入できませんでした。しかし、それを機能させる方法があれば、NSMatchingFlags と BOOL も渡して、その方法と同じ方法で処理するのがクールでしょう。できる?

アップデート

Dave DeLong からの回答のおかげで、ブロックを使用した新しいバージョンを入手できました。

@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

うまくいきました、ありがとう!

4

1 に答える 1

6

ブロック内から代入できるposのは、宣言を次のように変更するのと同じくらい簡単です。

NSUInteger pos = 0;

に:

__block NSUInteger pos = 0;

__blockキーワード の詳細:__block変数

于 2010-12-18T00:07:42.957 に答える