How do you use NSRegularExpression's replacementStringForResult:inString:offset:template:

前端 未结 6 875
清酒与你
清酒与你 2020-12-31 06:30

I have a series of characters that I want to match with a regular expression, and replace them with specific strings depending on what they are.

Example:

In

相关标签:
6条回答
  • 2020-12-31 07:06

    The answer of Dano works perfectly and following the idea of Pedro in the comments I wrapped the code into a category that takes a block that does the replacement part. This is very handy to use.

    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
    

    And here is how you use it to solve the initial question:

    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;
        }
    }];
    
    0 讨论(0)
  • 2020-12-31 07:12

    I needed a more generic solution for the same problem so I refined Dano's answer to a method like this, with a sample usage explained below:

    - (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;
    }
    

    Usage:

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

    Explanation: You just have to pass in the string to search for the matching substrings, along with the desired regexSearch pattern and a replacements dictionary containing the string pairs with the key being the substring to be replaced and the object with the desired replacement string.

    Output:

     //   This is the input string where i want to replace ONE TWO & THREE
    
    0 讨论(0)
  • 2020-12-31 07:21

    You should use

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

    or

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

    with string being "This is the input string where i want to replace 1 2 & 3" and template being either "ONE", "TWO" or "THREE".

    0 讨论(0)
  • 2020-12-31 07:22

    I was looking for something similar, but didn't like most of the answers here, so I wrote something inspired by how PHP does string replacement:

    @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
    

    To use it:

    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)"
    
    0 讨论(0)
  • 2020-12-31 07:24

    You can use the method within a for in loop using matchesInString:options:range:, which returns an array of matches as NSTextCheckingResults:

    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
    
    0 讨论(0)
  • 2020-12-31 07:28

    I recommend this, much shorter and uses a little memory : Another solution

    0 讨论(0)
提交回复
热议问题