【问题标题】:Efficient find and replace text in Objective C在 Objective C 中高效查找和替换文本
【发布时间】:2015-12-26 11:28:18
【问题描述】:

当用户在工具栏中键入文本时,我目前正在尝试查找替换文本字符串。到目前为止,我已经通过使用 ViewDidChange 方法更新文本视图并使用 stringByReplacingOccurrencesOfString 来完成此操作,如下面的代码所示。

这在查找和替换几个 (10-20) 字符串时效果很好,但是当使用 1,000 多个潜在替换执行此操作时,系统会变得非常滞后 - 您可以在键入时看到模拟器中的性能下降。

有谁知道如何提高效率?这是因为内存泄漏吗?我的一个想法是只对字符串中的最后一个单词使用替换字符串方法(即只查看用户输入的最后一个单词,但这只是对这可能如何加快速度的猜测,任何其他想法/想法/点击将不胜感激!

需要注意的另一点,如果用任何基于 unicode 的文本替换系统速度会更慢,有人知道解决此问题的具体方法吗?

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

    textView.text =  [textView.text stringByReplacingOccurrencesOfString:@"(?wi)\\bsmart\\b" withString: @"clever" options: NSRegularExpressionSearch range: NSMakeRange(0, [textView.text length]) ];
    textView.text =  [textView.text stringByReplacingOccurrencesOfString:@"(?wi)\\bfast\\b" withString: @"speedy" options: NSRegularExpressionSearch range: NSMakeRange(0, [textView.text length]) ];
    textView.text =  [textView.text stringByReplacingOccurrencesOfString:@"(?wi)\\bhappy\\b" withString: @"content" options: NSRegularExpressionSearch range: NSMakeRange(0, [textView.text length]) ];         
}

【问题讨论】:

    标签: objective-c


    【解决方案1】:

    目前,您正在对字符串进行多次传递,每个要替换的单词一次。你不需要这个;只需遍历字符串一次,动态替换单词,从而节省内存分配。

    您还可以预编译一个(巨大的)正则表达式并将其存储在实例变量中,以避免频繁重新编译。

    您还可以将选项移出非捕获组并将它们指定为全局标志(我不知道NSRegularExpression 的优化器在检测和提升多余重复标志方面有多好,但正则表达式优化器传统上是不是很聪明——如果有的话。)

    // ivars
    NSRegularExpression *regEx;
    NSDictionary *replacementRules;
    
    - (instancetype)init {
        ...
        replacementRules = @[
            @"smart": @"clever",
            @"fast":  @"speedy",
            @"happy": @"content"
        ];
    
        // 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];
        ...
    }
    
    - (void)textViewDidChange:(UITextView *)textView {
        ...
    
        // 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;
    }
    

    【讨论】:

    • 谢谢,这看起来正是我所需要的,唯一的问题是我在第一行出现预期的“]”或“,”错误,最后几行出现“预期的表达式”错误:replacementRules =@[@“智能”:@“聪明”,@“快速”:@“快速”,@“快乐”:@“内容”];你知道为什么会这样吗?
    • @user1419810 我希望您没有将省略号 () 直接复制到您的代码中……
    • 不,我删除了省略号,但在 replacementRules 字典周围有错误,包括预期的“]”或“,”和“预期的表达式”错误。
    • @user1419810 实例变量也需要与其他变量相邻(在类中的{ ... } 之间'@interface@implementation)。除此之外,我刚刚编译了自己的代码,我真的不知道为什么会出现语法错误。
    【解决方案2】:

    但是,当使用 1,000 多个潜在替代品进行此操作时,系统会变得非常滞后

    这并不奇怪。请注意,-stringByReplacingOccurancesOfString: 创建了一个全新的目标副本。即使在一根小绳子上做 1000 多次以上也需要一点时间。或者,即使在一个足以包含 1000 多个子字符串的字符串上执行几次,也需要一些时间。

    任何性能改进工作的第一步都应该是衡量您现在获得的实际性能。您可以为此使用 Instruments。多次运行相同的测试,并获得完成您正在执行的任何任务所需时间的基线。然后开始进行更改并衡量每一项,看看你在哪里得到了真正的改进。

    当您准备好开始进行更改时,我会尝试切换到使用单个可变字符串和-replaceOccurrencesOfString:withString:options:range: 之类的方法,而不是您当前的方法。这至少应该消除你现在正在做的大部分复制。

    【讨论】:

    • replaceOccurrencesOfString:withString:options:range: 对检测单词没有任何好处(它将用speedylane 代替fastlane 等)。此外,除非该方法对字符串的状态过于聪明,否则多次调用它会导致永久复制和重新分配(因为如果匹配和替换字符串的长度不同,则需要移动字符。)。如果性能是一个问题,一个人应该真正构建一个可变字符串,对,但应该增量地做,总是附加到尾部(正如我在回答中所证明的那样)。
    【解决方案3】:

    我想不出更好的正则表达式应用程序。

    请参阅:NSRegularExpression,以及这篇文章:

    http://www.raywenderlich.com/30288/nsregularexpression-tutorial-and-cheat-sheet

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-29
      相关资源
      最近更新 更多