Замените совпадения регулярных выражений в атрибутированной строке с изображением в Objective-C

Моя цель — сохранить информацию для строки с атрибутами в Parse.com. Я решил придумать кодировку атрибутированного текста для моих изображений, которая работает, заменяя любую строку {X} в фигурных скобках соответствующим изображением. Например:

Picture of 2 colorless mana: {X}

Должна создавать строку с атрибутами, в которой {X} заменяется изображением. Это то, что я пробовал:

NSString *formattedText = @"This will cost {2}{PW}{PW} to cast.";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(?<=\\{)[^}]+(?=\\})" options:NSRegularExpressionAnchorsMatchLines
                                                                         error:nil];
NSArray *matches = [regex matchesInString:formattedText
                                  options:kNilOptions
                                    range:NSMakeRange(0, formattedText.length)];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:formattedText];
for (NSTextCheckingResult *result in matches)
{
    NSString *match = [formattedText substringWithRange:result.range];
    NSTextAttachment *imageAttachment = [NSTextAttachment new];
    imageAttachment.image = [UIImage imageNamed:[NSString stringWithFormat:@"Mana%@.png", match]];
    NSAttributedString *replacementForTemplate = [NSAttributedString attributedStringWithAttachment:imageAttachment];
    [attributedString replaceCharactersInRange:result.range
                          withAttributedString:replacementForTemplate];
}
[_textView setAttributedText:attributedString];

В настоящее время у этого подхода есть две проблемы:

  • Фигурные скобки не заменяются, только текст внутри них.
  • Диапазон для каждого совпадения меняется, потому что меняется сама строка, и она становится больше с каждой заменой, исходный текст которой имеет длину > 1. Вот как это выглядит:

изображение


person michaelsnowden    schedule 21.07.2014    source источник


Ответы (1)


Две проблемы:

Брекеты не заменяются. Это потому, что вы используете утверждения, которые не считаются частью совпадения. Сопоставление, которое вы делаете с вашим шаблоном, содержит только то, что находится внутри фигурных скобок. Вместо этого используйте этот шаблон:

\{([^}]+)\}

Это: сопоставьте фигурную скобку, за которой следует одна или несколько вещей, не являющихся закрывающими фигурными скобками в группе захвата, за которыми следует закрывающая фигурная скобка. Весь матч теперь включает скобки.

Однако это создает еще одну проблему — вы используете заключенные биты для выбора заменяющего изображения. Небольшое изменение, чтобы исправить это: внутренняя группа захвата теперь содержит эту информацию, а не всю группу. Длина группы захвата указывает диапазон необходимой подстроки.

NSUInteger lengthOfManaName = [result rangeAtIndex:1].length;
NSString manaName = [match substringWithRange:(NSRange){1, lengthOfManaName}];
imageAttachment.image = [UIImage imageNamed:[NSString stringWithFormat:@"Mana%@.png", manaName]];

Вторая проблема: меняется длина строки. Просто перечислите в обратном порядке:

for (NSTextCheckingResult *result in [matches reverseObjectEnumerator])
{
    //...
}

Изменения диапазонов ближе к концу строки теперь не повлияют на более ранние диапазоны.

person jscs    schedule 21.07.2014
comment
Работал как шарм. Большое спасибо! - person michaelsnowden; 22.07.2014
comment
Конечно, @doctordoder. - person jscs; 22.07.2014
comment
reverseObjectEnumerator...спасибо...решение было передо мной. - person Matteo Gobbi; 02.10.2015