2

我的目标是将属性字符串的信息存储在 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时,它的范围会更大。这是它的样子:

一个图像

4

1 回答 1

7

两个问题:

大括号没有被替换。那是因为您正在使用断言,这些断言不计入匹配项。您使用模式进行的匹配仅包含大括号内的内容。请改用此模式:

\{([^}]+)\}

那就是:匹配一个大括号,后跟一个或多个不是捕获组中的右大括号的东西,然后是一个右大括号。整场比赛现在包括大括号。

但是,这引入了另一个问题——您正在使用封闭的位来选择替换图像。解决此问题的小改动:内部捕获组现在保存该信息,而不是整个组。捕获组的长度告诉您所需子字符串的范围。

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])
{
    //...
}

对字符串末尾范围的更改现在不会影响之前的范围。

于 2014-07-21T21:07:17.253 回答