| if (maxSplits == 0) | if (maxSplits == 0) | ||||
| return @[ self ]; | return @[ self ]; | ||||
| static NSRegularExpression *regexp; | |||||
| static NSRegularExpression *regex; | |||||
| static dispatch_once_t onceToken; | static dispatch_once_t onceToken; | ||||
| dispatch_once(&onceToken, ^{ | dispatch_once(&onceToken, ^{ | ||||
| regexp = [@"(?:^|\\S|$)+" regularExpression]; | |||||
| regex = [@"^\\S*|(?<=\\s)$|\\S+" regularExpression]; | |||||
| }); | }); | ||||
| NSMutableArray <NSString *> *components = [NSMutableArray array]; | NSMutableArray <NSString *> *components = [NSMutableArray array]; | ||||
| [regexp enumerateMatchesInString:self | |||||
| options:(NSMatchingOptions) 0 | |||||
| range:self.fullRange | |||||
| usingBlock:^(NSTextCheckingResult * _Nullable result, | |||||
| NSMatchingFlags flags, | |||||
| BOOL * _Nonnull stop) { | |||||
| if ( dropEmptyString | |||||
| && result.range.length == 0) { | |||||
| // Nothing. | |||||
| } else if (components.count < maxSplits) { | |||||
| [components addObject:[self substringWithRange:result.range]]; | |||||
| } else { | |||||
| [components addObject:[self substringWithRange:[self rangeToEndFrom:result.range]]]; | |||||
| *stop = YES; | |||||
| } | |||||
| }]; | |||||
| [regex enumerateMatchesInString:self | |||||
| options:(NSMatchingOptions) 0 | |||||
| range:self.fullRange | |||||
| usingBlock:^(NSTextCheckingResult * _Nullable result, | |||||
| NSMatchingFlags flags, | |||||
| BOOL * _Nonnull stop) { | |||||
| if ( dropEmptyString | |||||
| && result.range.length == 0) { | |||||
| // Nothing. | |||||
| } else if (components.count < maxSplits) { | |||||
| [components addObject:[self substringWithRange:result.range]]; | |||||
| } else { | |||||
| [components addObject:[self substringWithRange:[self rangeToEndFrom:result.range]]]; | |||||
| *stop = YES; | |||||
| } | |||||
| }]; | |||||
| return components; | return components; | ||||
| } | } | ||||
| -(NSRegularExpression *) regularExpressionWithOptions:(NSRegularExpressionOptions)options { | -(NSRegularExpression *) regularExpressionWithOptions:(NSRegularExpressionOptions)options { | ||||
| NSError *error; | NSError *error; | ||||
| NSRegularExpression *regexp = [NSRegularExpression regularExpressionWithPattern:self | |||||
| options:options | |||||
| error:&error]; | |||||
| NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:self | |||||
| options:options | |||||
| error:&error]; | |||||
| if (error) { | if (error) { | ||||
| if (NSString.SA_NSStringExtensions_RaiseRegularExpressionCreateException == YES) | if (NSString.SA_NSStringExtensions_RaiseRegularExpressionCreateException == YES) | ||||
| [NSException raise:@"SA_NSStringExtensions_RegularExpressionCreateException" | [NSException raise:@"SA_NSStringExtensions_RegularExpressionCreateException" | ||||
| return nil; | return nil; | ||||
| } | } | ||||
| return regexp; | |||||
| return regex; | |||||
| } | } | ||||
| /**********************************************/ | /**********************************************/ | ||||
| **********************************************/ | **********************************************/ | ||||
| -(NSArray <NSString *> *) matchesForRegex:(NSRegularExpression *)regex { | -(NSArray <NSString *> *) matchesForRegex:(NSRegularExpression *)regex { | ||||
| NSMutableArray <NSString *> *matches = [NSMutableArray arrayWithCapacity:regex.numberOfCaptureGroups]; | |||||
| [regex enumerateMatchesInString:self | |||||
| options:(NSMatchingOptions) 0 | |||||
| range:self.fullRange | |||||
| usingBlock:^(NSTextCheckingResult * _Nullable result, | |||||
| NSMatchingFlags flags, | |||||
| BOOL *stop) { | |||||
| [NSIndexSet from:0 | |||||
| for:result.numberOfRanges | |||||
| do:^(NSUInteger idx) { | |||||
| NSString *resultString = ([result rangeAtIndex:idx].location == NSNotFound | |||||
| ? @"" | |||||
| : [self substringWithRange:[result rangeAtIndex:idx]]); | |||||
| [matches addObject:resultString]; | |||||
| }]; | |||||
| return [self matchesForRegex:regex | |||||
| all:NO]; | |||||
| *stop = YES; | |||||
| }]; | |||||
| return matches; | |||||
| } | } | ||||
| -(NSArray <NSArray <NSString *> *> *) allMatchesForRegex:(NSRegularExpression *)regex { | -(NSArray <NSArray <NSString *> *> *) allMatchesForRegex:(NSRegularExpression *)regex { | ||||
| NSMutableArray <NSMutableArray <NSString *> *> *matches = [NSMutableArray arrayWithCapacity:regex.numberOfCaptureGroups]; | |||||
| [NSIndexSet from:0 | |||||
| for:regex.numberOfCaptureGroups | |||||
| do:^(NSUInteger idx) { | |||||
| [matches addObject:[NSMutableArray array]]; | |||||
| }]; | |||||
| return [self matchesForRegex:regex | |||||
| all:YES]; | |||||
| } | |||||
| /* Helper method (private). | |||||
| */ | |||||
| -(NSArray *) matchesForRegex:(NSRegularExpression *)regex | |||||
| all:(BOOL)all { | |||||
| NSMutableArray *matches = [NSMutableArray array]; | |||||
| [regex enumerateMatchesInString:self | [regex enumerateMatchesInString:self | ||||
| options:(NSMatchingOptions) 0 | options:(NSMatchingOptions) 0 | ||||
| range:self.fullRange | range:self.fullRange | ||||
| usingBlock:^(NSTextCheckingResult * _Nullable result, | usingBlock:^(NSTextCheckingResult * _Nullable result, | ||||
| NSMatchingFlags flags, | NSMatchingFlags flags, | ||||
| BOOL *stop) { | BOOL *stop) { | ||||
| if (all) | |||||
| [matches addObject:[NSMutableArray array]]; | |||||
| [NSIndexSet from:0 | [NSIndexSet from:0 | ||||
| for:result.numberOfRanges | for:result.numberOfRanges | ||||
| do:^(NSUInteger idx) { | do:^(NSUInteger idx) { | ||||
| NSString *resultString = ([result rangeAtIndex:idx].location == NSNotFound | NSString *resultString = ([result rangeAtIndex:idx].location == NSNotFound | ||||
| ? @"" | ? @"" | ||||
| : [self substringWithRange:[result rangeAtIndex:idx]]); | : [self substringWithRange:[result rangeAtIndex:idx]]); | ||||
| [matches[idx] addObject:resultString]; | |||||
| if (all) { | |||||
| [((NSMutableArray *) matches.lastObject) addObject:resultString]; | |||||
| } else { | |||||
| [matches addObject:resultString]; | |||||
| } | |||||
| }]; | }]; | ||||
| if (!all) | |||||
| *stop = YES; | |||||
| }]; | }]; | ||||
| return matches; | return matches; | ||||
| } | } | ||||
| withTemplate:(NSString *)template | withTemplate:(NSString *)template | ||||
| regularExpressionOptions:(NSRegularExpressionOptions)regexpOptions | regularExpressionOptions:(NSRegularExpressionOptions)regexpOptions | ||||
| matchingOptions:(NSMatchingOptions)matchingOptions { | matchingOptions:(NSMatchingOptions)matchingOptions { | ||||
| NSRegularExpression *regexp = [pattern regularExpressionWithOptions:regexpOptions]; | |||||
| NSTextCheckingResult *match = [regexp firstMatchInString:self | |||||
| options:matchingOptions | |||||
| range:self.fullRange]; | |||||
| NSRegularExpression *regex = [pattern regularExpressionWithOptions:regexpOptions]; | |||||
| NSTextCheckingResult *match = [regex firstMatchInString:self | |||||
| options:matchingOptions | |||||
| range:self.fullRange]; | |||||
| if ( match | if ( match | ||||
| && match.range.location != NSNotFound) { | && match.range.location != NSNotFound) { | ||||
| return [self stringByReplacingCharactersInRange:match.range | return [self stringByReplacingCharactersInRange:match.range | ||||
| withString:[regexp replacementStringForResult:match | |||||
| inString:self | |||||
| offset:0 | |||||
| template:template]]; | |||||
| withString:[regex replacementStringForResult:match | |||||
| inString:self | |||||
| offset:0 | |||||
| template:template]]; | |||||
| } else { | } else { | ||||
| return self; | return self; | ||||
| } | } | ||||
| withTemplate:(NSString *)template | withTemplate:(NSString *)template | ||||
| regularExpressionOptions:(NSRegularExpressionOptions)regexpOptions | regularExpressionOptions:(NSRegularExpressionOptions)regexpOptions | ||||
| matchingOptions:(NSMatchingOptions)matchingOptions { | matchingOptions:(NSMatchingOptions)matchingOptions { | ||||
| NSRegularExpression *regexp = [pattern regularExpressionWithOptions:regexpOptions]; | |||||
| NSTextCheckingResult *match = [regexp firstMatchInString:self | |||||
| options:matchingOptions | |||||
| range:self.fullRange]; | |||||
| NSRegularExpression *regex = [pattern regularExpressionWithOptions:regexpOptions]; | |||||
| NSTextCheckingResult *match = [regex firstMatchInString:self | |||||
| options:matchingOptions | |||||
| range:self.fullRange]; | |||||
| if ( match | if ( match | ||||
| && match.range.location != NSNotFound) { | && match.range.location != NSNotFound) { | ||||
| NSString *replacementString = [regexp replacementStringForResult:match | |||||
| inString:self | |||||
| offset:0 | |||||
| template:template]; | |||||
| NSString *replacementString = [regex replacementStringForResult:match | |||||
| inString:self | |||||
| offset:0 | |||||
| template:template]; | |||||
| [self replaceCharactersInRange:match.range | [self replaceCharactersInRange:match.range | ||||
| withString:replacementString]; | withString:replacementString]; | ||||
| } | } |