这是一个合理的Objective-C块实现吗?

4
我想要一个NSRegularExpression的变体,它的方法是– stringByReplacingMatchesInString:options:range:withTemplate:,但是它采用块而不是模板。 块的返回值将用作替换值。 这比模板更灵活,可以想象一下,有点像在Perl正则表达式中使用/e修饰符。
所以我编写了一个类别来添加该方法。这就是我想到的:
@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

非常好,谢谢!

1个回答

6
能够在块内部分配给pos,只需将声明更改为:
NSUInteger pos = 0;

致:

__block NSUInteger pos = 0;

__block关键字的更多信息:__block变量


2
完全合理,就像“Dave说的一样”。 :) - bbum
太棒了,谢谢!我会使用代码块更新问题的新版本。 - theory

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接