¿Es esta una cuerdo Objective-C Bloque de implementación?
-
11-10-2019 - |
Pregunta
Yo quería una variación del método de – stringByReplacingMatchesInString:options:range:withTemplate:
NSRegularExpression que toma un bloque en lugar de una plantilla. El valor de retorno del bloque se utiliza como valor de reemplazo. Esto es más flexible que una plantilla, como se puede imaginar. Tipo de como utilizar el modificador /e
en las expresiones regulares de Perl.
Así que escribió una categoría para añadir el método. Esto es lo que ocurrió:
@implementation NSRegularExpression (Block)
- (NSString *)stringByReplacingMatchesInString:(NSString *)string
options:(NSMatchingOptions)options
range:(NSRange)range
usingBlock:(NSString* (^)(NSTextCheckingResult *result))block
{
NSMutableString *ret = [NSMutableString string];
NSUInteger pos = 0;
for (NSTextCheckingResult *res in [self matchesInString:string options:options range:range]) {
if (res.range.location > pos) {
[ret appendString:[string substringWithRange:NSMakeRange(pos, res.range.location - pos)]];
}
pos = res.range.location + res.range.length;
[ret appendString:block(res)];
}
if (string.length > pos) {
[ret appendString:[string substringFromIndex:pos]];
}
return ret;
}
@end
Este es mi primer intento de jugar con bloques de C. Objetivo Se siente un poco raro, pero parece que funciona bien. Tengo un par de preguntas sobre el mismo, sin embargo:
- ¿Esto parece ser una manera sensata para poner en práctica un procedimiento de este tipo?
- ¿Hay alguna manera de poner en práctica sus partes internas usando
-enumerateMatchesInString:options:range:usingBlock:
? Lo probé, pero no podía asignar apos
desde dentro del bloque. Pero si había una manera de hacer que funcione, que sería genial para pasar las NSMatchingFlags y BOOL y tratarlos de la misma manera que ese método. Hacer de poder?
Actualizar
Gracias a la respuesta de Dave DeLong, tengo una nueva versión con un bloque:
@implementation NSRegularExpression (Block)
- (NSString *)stringByReplacingMatchesInString:(NSString *)string
options:(NSMatchingOptions)options
range:(NSRange)range
usingBlock:(NSString * (^)(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop))block
{
NSMutableString *ret = [NSMutableString string];
__block NSUInteger pos = 0;
[self enumerateMatchesInString:string options:options range:range usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop)
{
if (match.range.location > pos) {
[ret appendString:[string substringWithRange:NSMakeRange(pos, match.range.location - pos)]];
}
pos = match.range.location + match.range.length;
[ret appendString:block(match, flags, stop)];
}];
if (string.length > pos) {
[ret appendString:[string substringFromIndex:pos]];
}
return [NSString stringWithString:ret];
}
@end
Funciona muy bien, gracias!
Solución
Being able to assign to pos
from within the block would be as simple as changing the declaration from:
NSUInteger pos = 0;
To:
__block NSUInteger pos = 0;
More info on the __block
keyword: __block
Variables