你如何使用NSRegularExpression replacementStringForResult:in String:offset:template:

时间:2011-06-03 01:29:55

标签: regex cocoa-touch

我想要与正则表达式匹配的一系列字符,并根据它们的具体字符串替换它们。

示例:

In => “这是我要替换1 2& 3”的输入字符串

Out => “这是输入字符串,我想替换ONE TWO& THREE”

我目前通过使用空格作为分隔符拆分字符串,并逐个解析每个字符串,逐步重建字符串来完成此操作。我觉得这很难看,缺乏想象力,而且有点慢。

根据Apple文档,我应该可以使用replacementStringForResult:inString:offset:template:方法执行此操作。但是我似乎无法理解如何正确使用它。

6 个答案:

答案 0 :(得分:35)

您可以使用for inmatchesInString:options:range:循环中使用该方法,该NSTextCheckingResult会返回一个匹配数组NSError* error = NULL; NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:@"\\b[1-3]\\b" options:NSRegularExpressionCaseInsensitive error:&error]; NSString* yourString = @"This is the input string where i want to replace 1 2 & 3"; NSMutableString* mutableString = [yourString mutableCopy]; NSInteger offset = 0; // keeps track of range changes in the string // due to replacements. for (NSTextCheckingResult* result in [regex matchesInString:yourString options:0 range:NSMakeRange(0, [yourString length])]) { NSRange resultRange = [result range]; resultRange.location += offset; // resultRange.location is updated // based on the offset updated below // implement your own replace functionality using // replacementStringForResult:inString:offset:template: // note that in the template $0 is replaced by the match NSString* match = [regex replacementStringForResult:result inString:mutableString offset:offset template:@"$0"]; NSString* replacement; if ([match isEqualToString:@"1"]) { replacement = @"ONE"; } else if ([match isEqualToString:@"2"]) { replacement = @"TWO"; } else if ([match isEqualToString:@"3"]) { replacement = @"THREE"; } // make the replacement [mutableString replaceCharactersInRange:resultRange withString:replacement]; // update the offset based on the replacement offset += ([replacement length] - resultRange.length); } NSLog(@"mutableString: %@", mutableString); // mutableString: This is the input string where i want to replace ONE TWO & THREE s:

{{1}}

答案 1 :(得分:7)

Dano的答案完美无缺,并且在评论中遵循Pedro的想法我将代码包装成一个类别,该类别采用了替换部分的块。 这非常方便使用。

<强> NSRegularExpression + Replacement.h

@interface NSRegularExpression (Replacement)

- (NSString *)stringByReplacingMatchesInString:(NSString *)string
                                       options:(NSMatchingOptions)options
                                         range:(NSRange)range
                                      template:(NSString *)templ
                       withMatchTransformation: (NSString* (^) (NSString* element))transformation;

@end

<强> NSRegularExpression + Replacement.m

@implementation NSRegularExpression (Replacement)

- (NSString *)stringByReplacingMatchesInString:(NSString *)string
                                       options:(NSMatchingOptions)options
                                         range:(NSRange)range
                                      template:(NSString *)templ
                       withMatchTransformation: (NSString* (^) (NSString* element))transformation
{
    NSMutableString* mutableString = [string mutableCopy];
    NSInteger offset = 0; // keeps track of range changes in the string due to replacements.
    for (NSTextCheckingResult* result in [self matchesInString:string
                                                        options:0
                                                          range:range])
    {
        NSRange resultRange = [result range];
        resultRange.location += offset; // resultRange.location is updated based on the offset updated below

        // implement your own replace functionality using
        // replacementStringForResult:inString:offset:template:
        // note that in the template $0 is replaced by the match
        NSString* match = [self replacementStringForResult:result
                                                   inString:mutableString
                                                     offset:offset
                                                   template:templ];

        // get the replacement from the provided block
        NSString *replacement = transformation(match);

        // make the replacement
        [mutableString replaceCharactersInRange:resultRange withString:replacement];

        // update the offset based on the replacement
        offset += ([replacement length] - resultRange.length);
    }
    return mutableString;
}

@end

以下是您如何使用它来解决最初的问题:

NSString* yourString = @"This is the input string where i want to replace 1 2 & 3";
NSError* error = nil;
NSRegularExpression* regex = [NSRegularExpression
                              regularExpressionWithPattern:@"\\b[1-3]\\b"
                              options:0
                              error:&error];

return [regex stringByReplacingMatchesInString:yourString options:0 range:NSMakeRange(0, [yourString length]) template:@"$0" withMatchTransformation:^NSString *(NSString *match) {
    NSString* replacement;
    if ([match isEqualToString:@"1"]) {
        replacement = @"ONE";
    } else if ([match isEqualToString:@"2"]) {
        replacement = @"TWO";
    } else if ([match isEqualToString:@"3"]) {
        replacement = @"THREE";
    } else {
        return replacement;
    }
}];

答案 2 :(得分:2)

你应该使用

- (NSString *)stringByReplacingMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range withTemplate:(NSString *)template

- (NSUInteger)replaceMatchesInString:(NSMutableString *)string options:(NSMatchingOptions)options range:(NSRange)range withTemplate:(NSString *)template

字符串为“这是输入字符串,我想要替换1 2&amp; 3”,模板是“ONE”“TWO “”THREE“

答案 3 :(得分:1)

我需要一个针对同一问题的更通用的解决方案,所以我对Dano对这样的方法的回答进行了细化,下面介绍了示例用法:

- (NSMutableString *)replaceSubstringsInString:(NSString*)string
                                    usingRegex:(NSString*)searchRegex
                              withReplacements:(NSDictionary*)replacements {

    NSMutableString *newString = [string mutableCopy];
    __block NSInteger offset = 0;

    NSError *error = NULL;

    NSRegularExpression *regex = [NSRegularExpression
                                  regularExpressionWithPattern:searchRegex
                                  options:0
                                  error:&error];

    [regex enumerateMatchesInString:string
                            options:0
                              range:NSMakeRange(0, [string length])
                         usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){

                             NSRange resultRange = [match range];
                             resultRange.location += offset;

                             NSString *substring = [string substringWithRange:match.range];

                             __block NSString* replacement;

                             [replacements enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {

                                 if ([key isEqualToString:substring]) {
                                     replacement = obj;
                                 }

                             }];

                             [newString replaceCharactersInRange:resultRange withString:replacement];

                             offset += ([replacement length] - resultRange.length);
                         }];

    return newString;
}

<强>用法:

NSString *string = @"This is the input string where i want to replace 1 2 & 3";
NSString *searchRegex = @"\\b[1-3]\\b";
NSDictionary *replacements = @{@"1":@"ONE",@"2":@"TWO",@"3":@"THREE"};

NSMutableString *result = [self replaceSubstringsInString:string
                                               usingRegex:searchRegex
                                         withReplacements:replacements];

<强>说明: 您只需要传递string来搜索匹配的子字符串,以及所需的regexSearch模式和replacements 字典,其中包含字符串对key是要替换的子字符串,object是所需的替换字符串。

<强>输出:

 //   This is the input string where i want to replace ONE TWO & THREE

答案 4 :(得分:0)

我正在寻找类似的东西,但不喜欢这里的大多数答案,所以我写了一些灵感来自PHP如何替换字符串的东西:

@implementation NSString (preg_replace)

- (instancetype)stringByReplacingMatchesFromRegularExpression:(NSRegularExpression *)regularExpression replacementBlock:(NSString * (^)(NSArray *matches))replacementBlock
{
    NSMutableString *finalString = self.mutableCopy;
    NSUInteger offset = 0;

    for (NSTextCheckingResult *match in [regularExpression matchesInString:self options:0 range:NSMakeRange(0, self.length)]) {
        NSMutableArray *matches = [NSMutableArray array];
        for (NSUInteger index = 0; index < match.numberOfRanges; ++index) {
            [matches addObject:[self substringWithRange:[match rangeAtIndex:index]]];
        }
        NSString *replacementString = replacementBlock(matches.copy);

        [finalString replaceCharactersInRange:NSMakeRange(match.range.location + offset, match.range.length) withString:replacementString];
        offset += replacementString.length - match.range.length;
    }

    return finalString;
}

@end

使用它:

NSRegularExpression *expression = [[NSRegularExpression alloc] initWithPattern:@"[0-9A-F]{2}" options:0 error:nil];
NSString *string = @"AB-DE-EF";
NSString *result = [string stringByReplacingMatchesFromRegularExpression:expression replacementBlock:^NSString *(NSArray *matches) {
    return [NSString stringWithFormat:@"(%@)", [matches[0] lowercaseString]];
}];
NSLog(@"Result = %@", result); // "(ab)-(de)-(ef)"

答案 5 :(得分:-2)

我推荐这个,更短,并使用一点内存: Another solution