Как вы используете замену NSRegularExpressionStringForResult: inString: offset: template:
У меня есть серия символов, которые я хочу сопоставить с регулярным выражением, и заменяю их на определенные строки в зависимости от того, что они есть.
Пример:
In = > "Это строка ввода, где я хочу заменить 1 2 и 3"
Out = > "Это строка ввода, где я хочу заменить ONE TWO и THREE"
В настоящее время я делаю это, разбивая строку, используя пробелы, в качестве разделителя, и разбору каждой строки отдельно, постепенно перестраивая строку. Я чувствую, что это уродливо, и у него нет воображения, и что-то медленное.
Согласно документации Apple, я должен сделать это, используя метод replacementStringForResult:inString:offset:template:
. Однако я не могу понять, как правильно его использовать.
Ответы
Ответ 1
Вы можете использовать метод в цикле for in
, используя matchesInString:options:range:
, который возвращает массив совпадений как NSTextCheckingResult
s:
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
Ответ 2
Ответ Dano отлично работает и, следуя идее Педро в комментариях, я завернул код в категорию, которая берет блок, который выполняет замену.
Это очень удобно использовать.
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;
}
}];
Ответ 3
Вы должны использовать
- (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 и 3", а шаблон - "ONE", "TWO" или "THREE".
Ответ 4
Мне понадобилось более общее решение для одной и той же проблемы, поэтому я уточнил 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
Ответ 5
Я искал что-то подобное, но мне не понравилось большинство ответов здесь, поэтому я написал что-то, вдохновленное тем, что 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)"
Ответ 6
Я рекомендую это, намного короче и использует небольшую память:
Другое решение