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:

  1. ¿Esto parece ser una manera sensata para poner en práctica un procedimiento de este tipo?
  2. ¿Hay alguna manera de poner en práctica sus partes internas usando -enumerateMatchesInString:options:range:usingBlock: ? Lo probé, pero no podía asignar a pos 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!

¿Fue útil?

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top