iOS ObjectiveC查找和替换/正则表达式

时间:2015-10-07 13:04:06

标签: objective-c regex

我正在使用以下内容查找和替换文本作为用户键入textView

- (void)textViewDidChange:(UITextView *)textView {
    if (textView != self.inputToolbar.contentView.textView) {
        return;
    }

    NSRegularExpression *regEx;
    NSDictionary *replacementRules = @{
                                       @"cheese ": @"ham ",
                                       @"cat ": @"dog ",
                                       @"smile ": @"grin ",
                                       };

    // Build regular expression
    NSMutableArray *patterns = [NSMutableArray arrayWithCapacity:
                                replacementRules.count];

    for (NSString *str in replacementRules.allKeys) {
        [patterns addObject:[NSString stringWithFormat:@"\\b(%@)\\b", str]];
    }

    NSString *reStr = [patterns componentsJoinedByString:@"|"];

    regEx = [NSRegularExpression
             regularExpressionWithPattern:reStr
             options:NSRegularExpressionUseUnicodeWordBoundaries | NSRegularExpressionCaseInsensitive
             error:NULL];

    // our new string
    NSMutableString *s = [NSMutableString new];
    NSUInteger __block lastPos = 0;

    [regEx enumerateMatchesInString:textView.text
                            options:kNilOptions
                              range:(NSRange){ 0, textView.text.length }
                         usingBlock:^(NSTextCheckingResult *result,
                                      NSMatchingFlags flags,
                                      BOOL *stop) {

                             // Append the string from _before_ the match
                             [s appendString:[textView.text substringWithRange:(NSRange){
                                 lastPos, result.range.location - lastPos
                             }]];
                             lastPos = result.range.location + result.range.length;

                             // actually replace the string
                             NSString *captured = [textView.text substringWithRange:result.range];
                             [s appendString:replacementRules[captured]];
                         }];

    // append rest of string, from after the last match
    [s appendString:[textView.text substringWithRange:(NSRange){
        lastPos, textView.text.length - lastPos
    }]];

    textView.text = s;
}

这对于少于8个左右的单词的字符串工作正常,但随着字符串变得越来越长,键入速度显着减慢并变得滞后(无论是否执行文本的查找和替换。)这会严重影响用户体验,有谁知道为什么会这样或如何解决它?

2 个答案:

答案 0 :(得分:2)

您可以采取一些措施来提高速度。

首先,您需要将replacementRules字典和相应的正则表达式的初始化从textViewDidChange方法移开。每次最终用户键入或删除字符时构造字典和正则表达式都相当昂贵。

接下来,您应该更改正则表达式以减少捕获组的数量。目前,您的正则表达式如下所示:

\\b(cheese)\\b|\\b(cat)\\b|\\b(smile)\\b

您可以更改为等效的正则表达式

\\b(cheese|cat|smile)\\b

使正则表达式引擎的工作更容易。

最后,您应该制作一个标志,指示已发生替换,并从块内部进行设置。如果在您退出enumerateMatchesInString方法时设置了 标记,则可以立即返回,并完全跳过[s appendString...]部分。

答案 1 :(得分:0)

我不确定您是否需要使用正则表达式,因此如果您不这样做,此解决方案可能会更好一些。它会在按下空格之前输入最后一个单词,如果该单词匹配我们字典中的任何内容,我们会替换它,如果不是,我们会继续。

#import "ViewController.h"

@interface ViewController () <UITextViewDelegate>

@property (weak, nonatomic) IBOutlet UITextView *textView;
@property (strong, nonatomic) NSDictionary *words;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.words = @{ @"word": @"replace_word",
                    @"peter": @"replace_peter" };
}

- (void)textViewDidChange:(UITextView *)textView
{
    NSString *lastCharacter = [textView.text substringWithRange:NSMakeRange([textView.text length]-1, 1)];
    if([lastCharacter isEqualToString:@" "]) {
        NSMutableArray *words = (NSMutableArray *)[textView.text componentsSeparatedByString:@" "];
        NSString *lastWord = words[words.count - 2];
        for (NSString *word in self.words.allKeys) {
            if ([lastWord isEqualToString:word]) {
                lastWord = self.words[word];
                [words replaceObjectAtIndex:words.count - 2 withObject:lastWord];
                textView.text = [words componentsJoinedByString:@" "];
                break;
            }
        }
    }
}

@end