如何在objective-c中扫描一组字符串数组?

时间:2014-05-31 22:14:33

标签: ios objective-c xcode

所以我基本上有一系列的单词和短语。其中一些包含诅咒。我想创建一个方法,自动扫描数组中的每个单元的curses。如果它没有诅咒,请将其添加到新阵列。

我意识到我可以使用一堆if / else if语句和rangeOfString方法执行此操作,但我感到震惊的是我无法找到{{{ 1}}将同时搜索一堆单词。

我可能会忽略一些可用于扫描单个字符串以寻找子串数组的内容吗?

例如: 如果我有一系列短语,如:

NSString

我希望能够扫描然后派生出一个不包含以下数组中任何单词的新数组:

@[@"hey how are you",
  @"what is going on?",
  @"whats up dude?",
  @"do you want to get chipotle?"]

5 个答案:

答案 0 :(得分:1)

如果它是一个相当小的列表,只需迭代检查每个单词。

如果它相当大,请将“坏词”放在NSOrderedSet中,然后使用方法:containsObject:

如果要检查的字词数不小,您还可以将要检查的字词放在NSSet中,将“坏字”放在另一个NSSet中,并使用以下方法:{{ 1}}。

示例:

intersectsSet:

NSLog输出:
checkWords包含一个错误的词:'你怎么嘿'

答案 1 :(得分:1)

正如您所说:

  

感到震惊的是,我无法找到同时搜索大量单词的NSString方法

虽然这似乎是一个奇怪的反应 - 编程毕竟是关于构建解决方案,这里是一个解决方案,它使用单个方法同时搜索所有单词,但属于NSRegularExpression而不是{{1 }}

我们的样本数据:

NSString

要检查的最后一个示例行我们不匹配部分单词。增加了大写以测试不区分大小写的匹配。

我们构建一个RE以匹配任何停用词:

  • NSArray *sampleLines = @[@"Hey how are you", @"What is going on?", @"What’s up dude?", @"Do you want to get chipotle?", @"They are the youth" ]; NSArray *stopWords = @[@"you", @"hey"]; - 字边界,设置为在此示例中使用Unicode字边界的选项
  • \b - 一个非捕获组,只是使用它比捕获组快一点,它将与整个匹配相同
  • (?: ... ) - 或

exmaple stop words的模式:|

\b(?:you|hey)\b

迭代样本行,检查它们是否包含停用词,并在控制台上显示结果:

// don't forget to use \\ in a string literal to insert a backslash into the pattern
NSString *pattern = [NSString stringWithFormat:@"\\b(?:%@)\\b", [stopWords componentsJoinedByString:@"|"]];
NSError *error = nil;
NSRegularExpression *stopRE = [NSRegularExpression regularExpressionWithPattern:pattern
                                                                        options:(NSRegularExpressionCaseInsensitive | NSRegularExpressionUseUnicodeWordBoundaries)
                                                                          error:&error];
// always check error returns
if (error)
{
    NSLog(@"RE construction failed: %@", error);
    return;
}

正则表达式匹配应该是高效的,并且因为示例永远不会将单个单词或匹配复制为for (NSString *aLine in sampleLines) { // check for all words anywhere in line in one go NSRange match = [stopRE rangeOfFirstMatchInString:aLine options:0 range:NSMakeRange(0, aLine.length)]; BOOL containsStopWord = match.location != NSNotFound; NSLog(@"%@: %@", aLine, containsStopWord ? @"Bad" : @"OK"); } 个对象,所以这不应该创建许多临时对象作为枚举单个单词的方法。

HTH

答案 2 :(得分:0)

我做了两个嵌套的for循环。第一个循环扫描短语数组,第二个循环扫描单词数组。在半伪代码中,类似于:

NSMutableArray *filtered ... // etc.
// Loop over each phrase.
for (NSString *phrase in phrases) {

    // Let's assume it's acceptable
    bool good = true;

    for (NSString *word in words) {

        // If we find a single unwanted word, we'll no longer take it
        if ([phrase rangeOfString:word].location != NSNotFound) {
            good = false;

            break; // We don't need to keep iterating. 
                   // We already know it's not aceptable.
        }
    }

    if (good) [filtered insertObject:phrase];

}

答案 3 :(得分:0)

我会使用不同的方法。

我会使用方法indicesOfObjectsPassingTest:来扫描数组,返回不包含你的咒语的字符串对象的索引。然后,您可以获取生成的NSIndexSet并使用它来创建一个列出对象的新数组(使用方法objectsAtIndexes)。

你也可以使用2个嵌套循环,正如@ kevin9794所说,尽管他的代码需要一些修复:

NSMutableArray *filtered ... // etc.
// Loop over each phrase.
for (NSString *phrase in phrases) {
  BOOL hasSwears = NO;

  // Loop over each word

  for (NSString *swear in swears) 
  {

    // Do the check. This line will be executed once for combination
    // of items in the arrays.
    if ([string rangeOfString: swear].location != NSNotFound) 
    {
      hasSwears = YES;
      break;
    }
  }
  if (!hasSwears)
    [filtered insertObject:phrase];
}

该代码应该使用更长的rangeOfString形式,它允许您指定选项,并且可以选择进行不区分大小写的比较。

答案 4 :(得分:0)

老实说,我认为你的问题更多的是你认为,因为部分问题可以在随意的演讲中被掩盖,这必然会使问题变得简单。将句子分成单词很难。例子:

单词通常包含其他完整单词。例如“他们”包含“嘿”。你不能只搜索子串。

美国印刷惯例要求你不要在emdash周围放置空格。所以正确写的句子是“嘿 - 你好吗?”。你不能只是拆分空格和/或只是删除标点符号。

变音符号通常是可选的。即使在美国英语中,少数出版商 - 尤其是纽约人的出版商 - 也会使用diaresis;它看起来像一个变音符号但是标记了第二个元音,如果两个在一个单词中一起运行。像coöperate一样。然而,在某些语言中,他们改变了这个词 - 在德语中,变音符号是一个发音标记,例如将Apfel从单数与Äpfel复数区分开来。

那么,您究竟将Apple添加为简单的API级方法?选择不同选项的每个人应该做些什么?为您提供最适合您的方法的工具更为明智。

尽管如此,我认为我所描述的最简洁,最紧凑的形式是:

    NSArray *inputSentences =
        @[
            @"hey how are you",
            @"what is going on?",
            @"whats up dude?",
            @"do you want to get chipotle?"
        ];
    NSArray *forbiddenWords =
        @[@"you", @"hey"];

    NSSet *forbiddenWordsSet = [NSSet setWithArray:forbiddenWords];
    NSCharacterSet *nonLetterSet = 
                 [[NSCharacterSet letterCharacterSet] invertedSet];

    NSPredicate *predicate =
        [NSPredicate 
            predicateWithBlock:
                ^BOOL(NSString *evaluatedObject, NSDictionary *bindings)
                {
                    return ![forbiddenWordsSet intersectsSet:
                             [NSSet setWithArray:
                               [evaluatedObject 
                        componentsSeparatedByCharactersInSet:nonLetterSet]]];
                }];

    NSLog(@"%@", [inputSentences filteredArrayUsingPredicate:predicate]);

虽然你可能希望nonLetterSet改为whitespaceCharacterSet。自己判断。

谓词用于在没有显式循环和手动累积的情况下自动过滤集合。设置交叉点用于避免手动内部循环。唯一稍微不整洁的一点是必须使用块谓词,因为你必须应用预备逻辑。

从好的方面来说,大多数代码都是设置好的。您可以创建一次谓词,将其存储在某处,然后通过单个单行调用将其应用于代码中任何位置的任何数组或字符串集。

正如其他评论者所指出的,这将产生许多临时对象。