0

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

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

4

2 回答 2

10

为什么要另一个答案?

使用简单的解决方案有几个微妙的问题componentsSeparatedByString:

  1. 标点符号不作为单词分隔符处理。
  2. 除了空格字符(换行符、制表符)之外的空白被简单地删除。
  3. 在长字符串上会浪费大量内存。
  4. 它很慢。

例子

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

“基本上,”DHC 总结道,
“bokanovskification 包括一系列发展停滞。”</p>

...会导致...

– DHC – – 一系列 – 的 –</p>

...而正确的输出是:

“-”,DHC-,
“--一系列-的-。”</p>

解决方案

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

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

比较解决方案

这是一个适用于行话文件(1.6 MB,237,239 字)的简单演示项目。它比较了三种不同的解决方案:

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

执行

它的核心是替换循环:

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's 长度来确定单词的字符数。至少可以说,这是一个值得怀疑的方法。实际上,字符串length指定了用于对字符串进行编码的代码片段的数量,该值通常与人类假设的字符数不同。

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

于 2013-05-09T09:32:58.890 回答
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 提到的示例。文档在这里,这里有边界检测的具体讨论。

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

NSString 文档中有更多信息

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

于 2013-05-09T09:41:06.107 回答