【问题标题】:How to search a string for multiple multi-word phrases in Swift or Objective-C如何在 Swift 或 Objective-C 中搜索多个多词短语的字符串
【发布时间】:2020-07-03 16:58:18
【问题描述】:

我想解析大量字符串以查找固定短语或名称,然后将名称(如果找到)存储在顺序重要的数组中。

例如,以字符串开头,例如:

str = "The movie stars Robert Duvall and James Earl Jones and pits them against a villain played expertly by Brando in an action packed adventure."

我想搜索一组演员:

names = [Robert Duvall, Henry Fonda, Brando, Marlon Brando, Jane Fonda, James Earl Jones, Peter Fonda, Montgomery Clift] 等,其中演员可以有一个、两个或三个名字。

最初,我可以使用strpos 简单地检查三元组是否匹配,或者将字符串转换为三元组,然后像 James Earl Jones 中那样对三元组进行匹配。然后我可以删除他的名字并在其余部分中搜索其他双打或单个单词。但是,这种方法很快就会变得非常复杂,我想知道是否没有更优雅的方法。

//这条路看起来确实很乱……

NSArray *triples = [self getTriples:str];//get all combinations of three sequential words
NSArray *pieces = [NSMutableArray new];
NSMutableArray * matches = [NSMutableArray new];
for (long i = 0;i<[triples count];i++) {
   NSString *phrase = triples[i];
   for (long j = 0;j<[names count];j++) {
      NSString *name = names[j];
      if ([phrase caseInsensitiveCompare:name]==NSOrderedSame) {
         [matches addObject:phrase];
         //Rumps has two elements, before and after
         rumps = [str componentsSeparatedByString:phrase];
         NSString *start = rumps[0];
         NSString *end = rumps[1];
         //Search before for a name
         //search after for a name
      }
   }
}//end triples

感谢您的任何建议。

【问题讨论】:

  • 字符串“Marlon Brando and Brando saw Brando and Marlon Brando”的预期结果是什么?
  • 看看自然语言框架,它会在这个领域为你做很多工作。 developer.apple.com/documentation/naturallanguage/…
  • @pawello,预期的结果将是 [Marlon Brando],例如一个包含一个演员的数组,因此应该防止被骗。
  • 那么 [Marlon Brando] 和 [Brando] 是两个不同的数组?
  • 基本上我正在尝试搜索字符串并拉出提到的演员,以便按出现顺序获取演员数组。如果一个演员被提到两次,例如马龙白兰度和白兰度,那么在映射到演员之后,我可以使用类似 [[NSSet setWithArray:yourarray] allObjects];但是,我正在努力将字符串与可能使用的各种可能的演员名称进行比较。

标签: ios arrays objective-c swift strpos


【解决方案1】:

这是一个基于您的 names 字符串的想法。

  1. 用逗号分割names,并存储在数组中,比如a1
  2. 遍历a1,看看你的全名是否匹配
  3. 如果没有,请再次循环 a1 并将空格拆分为 a2

这里我不太清楚你的逻辑,但也许是这样?现在在这个内部循环中,你循环a2

  1. 如果a2 具有三个元素/名称,那么您认为不匹配?或者您可以检查所有可能的组合,只检查 3 个(已经检查了 123 个,然后是 132、213、231、312、321 和您完成了 3 个名称)。
  2. 如果它有两个元素只反向检查(21,你已经检查了 12)。
  3. 如果仍然不匹配,您可以检查 a2 的各个元素,如果这是您想要的,那么请检查 1、2(可能还有 3)。

您使用相应的a1 元素的任何匹配项 - 这就是您想要的,全名,对吗?

您可以使用索引集并将索引设置为a1 - 您找到的防止重复的演员。

【讨论】:

  • 根据您的回答,以及@CRD 的回答,听起来好像没有魔术,我必须一步一步地解决它。会试试这个
  • 没错!没有捷径,但你仍然可以巧妙地做到这一点。在任何地方,您都在字符串中检查演员的姓名,如果找到,您想从字符串中删除姓名以避免重复,因此请为初学者设置一个单独的函数。您在 2、4、5 和 6 中调用该函数。也可以为 4 创建一个函数来检查包含三个名称和三个索引的数组的字符串,然后您可以调用它,例如check3:( NSString * ) sentence names3:( NSArray&lt; NSString * &gt; * ) names3 i1:( int ) i1 i2:( int ) i2 i3:( int ) i3。哎呀,您可以将NSNotFound 传递给i3,并在6 中使用它。
  • 格式搞砸了,但您可以将其称为如下[check3:s names3:n i1:0 i2:2 i3:1],例如检查 132 等等。然后它会很好,简洁和模块化,当它运行时你会得到一种温暖的感觉——至少我听说过。
  • ...哎呀...我的意思是您可以使用NSNotFound 也可以以前签入5 ...
【解决方案2】:

这是一种可能的算法sketch,不会有真正的代码——事实上,在我写这篇文章时,它并不是用 Objective-C 或 Swift 编写的,它是一个算法 em> 可以用两种(和其他)语言实现。

在编码时你可能会发现算法遗漏了一些东西(即可能有错误,这是直接写在答案中的,它是一个草图!),在这种情况下,请返回并改进算法并重复。

我们的样品名单:

詹姆斯·厄尔·琼斯、詹姆斯、马龙·白兰度、厄尔·琼斯、白兰度、詹姆斯·厄尔

和示例文本:

James、James Earl 和 James Earl Jones 都定期见面喝咖啡

该算法基于观察结果:

[注意:在描述中,我们假设文本是从左到右的,并且匹配的搜索从左到右移动。该算法适用于从右到左的简单调整,对于混合方向的文本,它会变得更乱!]

  1. 匹配不能重叠。例如。 “James Earl”不是“James”“James Earl”。我们说匹配消耗了测试。

  2. 只有作为另一个前缀的名字需要注意,那些是*后缀的则不需要。例如,如果要查找“James”和“James Earl”,您必须首先查找后者避免在“James”上找到匹配然后错过“James Earl”,因为“James”上的匹配已经消耗了这些字符。但是可以同时搜索“Earl Jones”和“James Earl Jones”,后者将先匹配。

  3. 在不包含任何前缀的名称集合中,它们都可以使用正则表达式同时匹配。例如。 "James Earl Jones" 和 "Earl Jones" 可以通过 RE "James Earl Jones|Earl Jones" 匹配

  4. 如果您有前缀,因此您首先搜索较长的名称,较短名称的匹配只能出现在较长名称匹配的左侧。

该算法使用正则表达式匹配,由 Objective-C & Swift 中的NSRegularExpression 提供;和范围,由NSRange 提供,允许搜索字符串的一部分。

大纲:

  1. 对您的姓名进行排序。例如:

白兰度、厄尔·琼斯、詹姆斯、詹姆斯·厄尔、詹姆斯·厄尔·琼斯、马龙·白兰度

  1. 通过删除任何作为其紧随其后名称前缀的名称并放入第二个列表,将您的名称分成两个列表。例如

白兰度、厄尔·琼斯、詹姆斯·厄尔·琼斯、马龙·白兰度 詹姆斯,詹姆斯·厄尔

  1. 如果第二个列表不为空,则重复步骤 (2) 生成第三个列表,继续重复直到没有删除任何前缀。例如。我们的示例名称产生了 3 个列表:

白兰度、厄尔·琼斯、詹姆斯·厄尔·琼斯、马龙·白兰度 詹姆斯·厄尔 詹姆斯

  1. 使用交替将每个列表转换为正则表达式,以生成用于搜索的正则表达式列表。例如:

“白兰度|厄尔·琼斯|詹姆斯·厄尔·琼斯|马龙·白兰度”、“詹姆斯·厄尔”、“詹姆斯”

(此时我们意识到样本名称可能会更好,因为只有第一个 RE 需要更改。哦,好吧...)

现在我们准备好使用我们准备好的正则表达式来查找匹配项。

  1. 搜索范围设置为整个文本,匹配范围为空/无值。

  2. 当前RE设置为第一个

  3. 使用当前 RE 搜索 搜索范围 内的第一个匹配项以生成 匹配范围。如果没有新的匹配转到 (9)。例如。使用我们的示例,其中匹配范围由 [] 表示:

James、James Earl 和 [James Earl Jones] 都定期见面喝咖啡

  1. 将新的搜索范围设置为从当前搜索范围的开始到匹配范围的结束,前进当前RE,转到(6)。例如。名字的匹配顺序是:

James、James Earl 和 [James Earl Jones] 都定期见面喝咖啡 詹姆斯,[詹姆斯厄尔]和詹姆斯厄尔琼斯 [詹姆斯],詹姆斯·厄尔

  1. 我们现在有了我们的第一个匹配范围,记录下来,将新的搜索范围设置为从匹配范围的末尾到文本的末尾,如果这个新的搜索范围是非空的,则转到 6。

  2. 完成,我们有匹配列表。

如果您不想要实际匹配的列表,而只需要一组独特匹配,则可以随时累积一组匹配(例如 NSMutableSet/Set)。

玩得开心编码(和精炼、编码...)算法。如果你遇到了一个新问题,请参考这个问答,描述你的算法,展示你的实现,详细说明你的问题等等,毫无疑问有人会帮助你。 HTH。

【讨论】:

  • 谢谢,我会努力实现的!
猜你喜欢
  • 2019-12-06
  • 1970-01-01
  • 2018-09-03
  • 1970-01-01
  • 2014-01-10
  • 2014-03-14
  • 2012-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多