在NSString中查找并替换长单词?

时间:2013-05-09 06:58:08

标签: objective-c nsstring

我正在尝试编写一个搜索NSString的方法,确定字符串中的单个单词是否长度超过6个字符,并用其他单词替换该单词(任意类似“hello”)。

我从一个长段开始,我需要最终得到一个NSString对象,其格式和间距不受查找和替换的影响。

3 个答案:

答案 0 :(得分:10)

为什么要另一个答案?

使用componentsSeparatedByString:的简单解决方案存在一些微妙的问题:

  1. 标点符号不作为单词分隔符处理。
  2. 其他空格字符(换行符,制表符)被删除的空格。
  3. 在长字符串上浪费了大量内存。
  4. 这很慢。
  5. 实施例

    假设替换词“ - ”是一个像...的字符串

      

    “基本上”,D.H.C。得出的结论,
      “bokanovskification包括一系列逮捕发展。”

    ......会导致......

      

    - D.H.C. - 一系列 - 的 -

    ...虽然正确的输出是:

      

    “ - ,”D.H.C。 - , - “ - - 一系列的 - 。”

    解决方案

    幸运的是,在Cocoa中有一个更好但更简单的解决方案:-[NSString enumerateSubstringsInRange:options:usingBlock:]

    它提供了对options参数定义的子字符串的快速迭代。一种可能性是NSStringEnumerationByWords,它枚举所有实际上是真实单词的子串(在当前语言环境中)。它甚至可以检测不使用分隔符(空格)来分隔单词的语言中的单个单词,例如日语。

    比较解决方案

    Here's a simple demo project适用于行话文件(1.6 MB,237,239字)。它比较了三种不同的解决方案:

    1. componentsSeparatedByString:270 ms
    2. enumerateSubstringsInRange:125 ms
    3. stringByReplacingOccurrencesOfString,如@Monolo所述:200毫秒
    4. 实施

      它的核心是替换循环:

      NSMutableString *result = [NSMutableString stringWithCapacity:[originalString length]];
      __block NSUInteger location = 0;
      [originalString enumerateSubstringsInRange:(NSRange){0, [originalString length]}
                                         options:NSStringEnumerationByWords | NSStringEnumerationLocalized | NSStringEnumerationSubstringNotRequired
                                      usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
      
                                          if (substringRange.length > maxChar) {
                                              NSString *charactersBetweenLongWords = [originalString substringWithRange:(NSRange){ location, substringRange.location - location }];
                                              [result appendString:charactersBetweenLongWords];
                                              [result appendString:replaceWord];
                                              location = substringRange.location + substringRange.length;
                                          }
      
                                      }];
      [result appendString:[originalString substringFromIndex:location]];
      

      买者

      正如Monolo所指出的,建议的代码使用NSString的长度来确定单词的字符数。至少可以说,这是一个值得怀疑的方法。实际上,字符串length指定了用于对字符串进行编码的代码片段的数量,这个值通常与人类假定的字符数相符。

      由于术语“字符”在各种上下文中具有不同的含义,并且OP没有指定使用哪种字符计数,所以我只保留代码。如果您想要不同的计数,请参阅讨论该主题的文档:

答案 1 :(得分:2)

从答案中可以看出,有几种方法可以实现您的目标,但我个人更喜欢使用NSString类的stringByReplacingOccurrencesOfString:withString:options:range:方法,该方法完全取代了子串另一个字符串。

在您的情况下,我们需要使用NSRegularExpressionSearch选项,该选项将允许识别包含7个或更多字母的单词(即,当您声明时,超过6个字母)。

如果您使用\w * 字符表达式,您将自动获得Unicode支持,因此它可以使用与Apple(实际上是ICU)支持的语言一样多的语言。

它是这样的:

NSString *stringWithLongWords = @"There are some words of extended length in this text. One of them is Escher's. They will be identified with a regular expression and changed for some arbitrary word.";

NSString *overSixCharsPattern = @"(?w)\\b[\\w]{7,}\\b";
NSString *replacementString   = @"hello";

NSString *result = [stringWithLongWords stringByReplacingOccurrencesOfString: overSixCharsPattern
                                                                  withString: replacementString
                                                                     options: NSRegularExpressionSearch
                                                                       range: NSMakeRange(0, stringWithLongWords.length)];

\b表达式表示单词边界,确保整个单词匹配和替换。 w修饰符使\b使用更自然的单词边界定义。具体来说,它处理字符串“Escher's”,这是@NikolaiRuhe提到的例子。文档here,特别讨论了边界检测here

另请注意,文字NSString(即您直接在Objective-C源文件中键入的文字)在源代码中需要两个反斜杠才能在生成的字符串中生成一个反斜杠。

NSString documentation

中有更多信息

* 技术上\w匹配单词字符,其中还包括正则表达式使用的定义中的数字。

答案 2 :(得分:-2)

试试这个。

NSString *str  = @"Do any additional setup after loading the view, typically from a nib.";
NSMutableArray *array = [[str componentsSeparatedByString:@" "] mutableCopy];
for (int i = 0; i < [array count]; i++) {
    NSString *str_ = [array objectAtIndex:i];
    if ([str_ length] > 6)
        [array replaceObjectAtIndex:i withObject:@"Hello"];
}

然后再添加它们

str = [array componentsJoinedByString:@" "];