你将如何扫描objective-c中的一组子string的string数组?
所以我基本上有一些单词和短语。 其中一些包含诅咒。 我想创build一个方法,自动扫描数组中的每个单位的诅咒。 如果它没有诅咒,将它添加到一个新的数组。
我意识到我可以用一堆的if
/ else if
语句和rangeOfString
方法来做到这一点,但我感到震惊的是,我一直无法findNSString
的方法,将同时search一堆的单词。
有什么我可能忽略了,可以用来扫描一个string的子串的数组?
例如:如果我有一些短语如:
@[@"hey how are you", @"what is going on?", @"whats up dude?", @"do you want to get chipotle?"]
我希望能够扫描,然后派生一个新的数组,不包含任何从以下数组中的单词:
@[@"you", @"hey"]
如果它是一个相当小的列表,只需遍历它检查每个单词。
如果它比较大,把“坏词”放在NSOrderedSet
,然后使用方法: containsObject:
NSOrderedSet
如果要检查的单词数量不是很less,也可以将单词在NSSet
进行检查,并在另一个NSSet
使用“bad words”,并使用方法: intersectsSet:
NSSet
例:
NSArray *stringsToCheck = @[@"hey how are you", @"what is going on?", @"whats up dude?", @"do you want to get chipotle?"]; NSSet *badWords = [NSSet setWithArray:@[@"how", @"dude", @"yes"]]; for (NSString *line in stringsToCheck) { NSSet *checkWords = [NSSet setWithArray:[line componentsSeparatedByString:@" "]]; NSLog(@"checkWords: %@", checkWords); if ([checkWords intersectsSet:badWords]) { NSLog(@"checkWords contains a bad word in: '%@'", [[checkWords allObjects] componentsJoinedByString:@" "]); // Now search for the specific bad word if necessary. } }
NSLog输出:
checkWords包含一个坏词:“你怎么样,嘿,
正如你所说你是:
惊骇的是,我一直无法find一个
NSString
的方法,将同时search一堆字
虽然这似乎是一个奇怪的反应 – 编程是关于build立解决scheme毕竟,这里是一个解决scheme,使用单一的方法同时search所有的单词,但属于NSRegularExpression
而不是NSString
。
我们的样本数据:
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"];
最后一个样本行检查我们不匹配的部分单词。 添加大写以testing不区分大小写的匹配。
我们构造一个RE来匹配任何停用词:
-
\b
– 字边界,在本例中设置为使用Unicode字边界的选项 -
(?: ... )
– 一个没有捕获的组,只是因为它比捕获组稍微快一些,反正它和整个匹配一样 -
|
– 要么
用于exmaple停止词的模式: \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"); }
正则expression式匹配应该是有效的,并且作为例子从不拷贝与NSString
对象一样的单个单词或者匹配,所以不应该像列举单个单词的方法那样创build很多临时对象。
HTH
我会用不同的方法。
我将使用方法indexesOfObjectsPassingTest:扫描数组,返回不包含发誓的string对象的索引。 然后,您可以获取生成的NSIndexSet,并使用它创build一个列出对象的新数组(使用方法objectsAtIndexes)。
你也可以使用2个嵌套循环,就像@ kevin9794所说的,尽pipe他的代码需要一些修正:
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的更长的forms,可以让你指定选项,并且可以select进行不区分大小写的比较。
老实说,我认为你的问题在于,你认为这个问题越来越多,因为这个问题的一部分可以用随意的语言来掩盖,而这个问题一定会成为一个简单的问题。 把一个句子分成单词很难。 例子:
单词中经常包含其他完整的单词。 例如“他们”包含“嘿”。 你不能只search子string。
美国印刷公约规定,你不要把空格放在emdash周围。 所以正确的句子是“嘿,你好吗?” 你不能只分割空白和/或只是删除标点符号。
变音符通常是可选的。 即使在美国英语中,less数出版商 – 尤其是那些纽约人的出版商 – 则使用了一种减刑法; 它看起来像一个变音符号,但是如果两个元音一起运行,则标记第二个元音。 像cooperate。 然而,在某些语言中,他们改变了这个词 – 在德语中,变音符号是一个发音标记,例如将apfel单数从复数formsÄpfel中区分开来。
那么,苹果究竟会将API添加为一个简单的API级别的方法呢? 每个select不同select的人应该做什么? 只要给你工具来构build最适合你的方法就明智多了。
所有人都说,我认为你所描述的最简洁最紧凑的forms是:
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]);
尽pipe您可能希望将nonLetterSet设置为whitespaceCharacterSet
。 为自己判断。
谓词用于在没有显式循环和手动累加的情况下自动过滤集合。 设置十字路口用于避免手动内部循环。 唯一稍微不整洁的是不得不使用块谓词,因为你必须应用准备逻辑。
好的一面是,大部分代码都是安装的。 您可以创build谓词一次,将其存储在某个地方,然后将其应用于代码中任何位置的任何数组或string集合,只需一行即可。
正如其他评论者所指出的,这将产生大量的临时对象。
我会做两个嵌套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]; }