-->

Replacing numbers in an NSString with Objects from

2019-09-11 00:22发布

问题:

In a UITextView users can enter numbers formatted like {{1}} or {{177}}. In a preview field, much like here on SO I'd like to replace that pattern with a value from an NSArray, where the number corresponds to the row in the array.

I have two ideas to solve this:

  1. Count all occurrences with an NSRegularExpression, loop through them and replace them.
  2. Create a word-array out of the NSString and loop through the array, replacing occurrences and put the NSString back together.

Which of those two options is more performant and reliable? Is there another way?

-- update -- This is the regular expression to find the pattern: @"\\{\\{([1-9]|[1-9][0-9]|[1-9][0-9][0-9])\\}\\}". How can I use this in a loop with an integer to replace the pattern?

回答1:

Here's an answers using NSRegularExpression:

NSString * input = @"{{83}} fjsdkfjds {{122}}";

NSMutableString * strToMakeReplacements = [[NSMutableString alloc] initWithString:input];

NSError * error = nil;
NSRegularExpression * regex = [NSRegularExpression regularExpressionWithPattern:@"\\{\\{([1-9]|[1-9][0-9]|[1-9][0-9][0-9])\\}\\}" options:NSRegularExpressionCaseInsensitive    error:&error];

NSArray * matches = [regex matchesInString:input options:NSMatchingReportProgress range:NSMakeRange(0, [input length])];

for (int i = [matches count]-1; i>=0 ; i--) {
    NSTextCheckingResult * match = [matches objectAtIndex:i];

    NSRange matchRange = match.range;
    NSString * numString = [input substringWithRange:NSMakeRange(matchRange.location+2, matchRange.length-4)];
    NSInteger num = [numString intValue];

    NSString * replacementValue = [self replacementValueForNum:num]; // write this function yourself

    [strToMakeReplacements replaceCharactersInRange:match.range withString:replacementValue];
}

Note that you need to escape the slashes in your regex, so that it becomes \\{\\{([1-9]|[1-9][0-9]|[1-9][0-9][0-9])\\}\\}



回答2:

I would use the second approach since it seems more convenient than using regular expressions (although I'm admittedly not very experienced with them).

Given an input string NSString* input I would filter out not numeric characters as follows:

NSCharacterSet* notNumbersSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
NSArray * wholeNumbers = [input componentsSeparatedByCharactersInSet:notNumbersSet];

Now loop through the array of whole numbers:

for( NSString* numString in wholeNumbers ) {
    NSInteger num = [numString intValue];
    // ...
}


回答3:

A NSRegularExpression approach would be something like this –

NSRegularExpression * expression = [NSRegularExpression regularExpressionWithPattern:@"\\{\\{(\\d+?)\\}\\}"
                                                                             options:0
                                                                               error:nil];
NSMutableString * resultString = [aString mutableCopy];
NSTextCheckingResult * result;
NSUInteger location = 0;

/* Get the first match in the remaining string to search */
while ((result = [expression firstMatchInString:resultString options:0 range:NSMakeRange(location, [resultString length] - location)])) {

    /* Get the index of the array using the capture group 1 i.e. (\\d+?) */
    NSUInteger index = [[resultString substringWithRange:[result rangeAtIndex:1]] integerValue];

    /* Get the string that will replace the match */
    NSString * replacementString = [replacementStrings objectAtIndex:index];

    /* Replace the string */
    [resultString replaceCharactersInRange:result.range withString:replacementString];

    /* Skip to the end of the replaced string */
    location = result.range.location + [replacementString length];
}

Since our replacement strings come from an array I doubt we have a single statement solution to this. Here we find a match, replace it appropriately and then search the rest of the string for a match. We repeat this there are no more results.