【问题标题】:iOS Swift: looking for ranges of matching word in a stringiOS Swift:在字符串中查找匹配单词的范围
【发布时间】:2020-12-14 06:41:53
【问题描述】:

我需要创建一个函数来返回给定字符串中匹配单词的范围,例如,给定以下句子:

嘿,兄弟!你的兄弟也是她的兄弟。

我想在与单词“bro”匹配的句子中找到Range的数组,它应该匹配确切的单词(不区分大小写),所以“bro”应该只匹配“bro”而不是“brother” .

我想过:

  1. 拆分句子,例如"hey", "bro", "your", "brother", "is", "also", "her", "brother"
  2. 将每个单词映射到具有范围的单词,例如“嘿”会变成["hey", 0...2]
  3. 过滤和映射单词和范围数组,匹配“bro”

第 2 步需要进行一些处理,以确保每个单词(在句子中)的范围可以映射到正确的单词,例如第一个“兄弟”和第二个“兄弟”应该有不同的范围,具体取决于它们所在的位置。

有什么更聪明的方法吗?

编辑:

对不起,我忘了说,不使用Regex的原因是有时单词中有一个点,例如:

篮子里有橘子。

从上面的句子中,使用正则表达式查找字符串“or.ge”也会匹配“orange”。

【问题讨论】:

    标签: ios swift regex string


    【解决方案1】:

    我在 Playground 中测试过,您可以使用此扩展来获取与此 reg ex 匹配的值。

    extension String {
        func ranges(of substring: String, options: CompareOptions = [], locale: Locale? = nil) -> [Range<Index>] {
            var ranges: [Range<Index>] = []
            while ranges.last.map({ $0.upperBound < self.endIndex }) ?? true,
                  let range = self.range(of: substring, options: options, range: (ranges.last?.upperBound ?? self.startIndex)..<self.endIndex, locale: locale)
            {
                ranges.append(range)
            }
            return ranges
        }
    }
    
    let searchString = "bro"
    var str = "Hey, bro! Your brother is also her brother."
    var reg = str.ranges(of: "(?<![\\p{L}\\d])\(searchString)(?![\\p{L}\\d])", options: [.regularExpression, .caseInsensitive])
    
    str.removeSubrange(reg.first!)
    
    print(str)
    

    归功于, iOS - regex to match word boundary, including underscore

    【讨论】:

      【解决方案2】:

      一个简单的解决方案是使用带有\b 的正则表达式来匹配“单词边界”,例如

      let searchString = "bro"
      let sentence = "Hey, Bro! Your brother is also her brother."
      let regex = try! NSRegularExpression(pattern: #"\b\#(searchString)\b"#, options: .caseInsensitive)
      regex.enumerateMatches(in: sentence, range: NSRange(sentence.startIndex..., in: sentence)) { match, _, _ in
          guard let match = match else { return }
          print(match.range)
      
          // or, if you want a String.Range
      
          if let range = Range(match.range, in: sentence) {
              print(sentence[range])
          }
      }
      

      还有其他更丰富的 API(例如 Natural Language 框架),虽然并不完美,但可以提供更丰富的自然语言文本解析。例如,下面将区分动词“saw”和名词“saw”:

      import NaturalLanguage
      
      let text = "I saw the hammer. I did not see a saw."
      
      let tagger = NLTagger(tagSchemes: [.lexicalClass])
      tagger.string = text
      let options: NLTagger.Options = [.omitWhitespace, .joinContractions]
      tagger.enumerateTags(in: text.startIndex..<text.endIndex, unit: .word, scheme: .lexicalClass, options: options) { tag, range in
          guard let tag = tag else { return true }
      
          print(tag, String(text[range]))
          return true
      }
      

      制作:

      NLTag(_rawValue: 代词) 我
      NLTag(_rawValue: Verb) 看到
      NLTag(_rawValue:Determiner)
      NLTag(_rawValue: 名词) 锤
      NLTag(_rawValue: SentenceTerminator) 。
      NLTag(_rawValue: 代词) 我
      NLTag(_rawValue: Verb) 做了
      NLTag(_rawValue: 副词) 不是
      NLTag(_rawValue: 动词) 见
      NLTag(_rawValue: 确定器)
      NLTag(_rawValue: 名词) 锯
      NLTag(_rawValue: SentenceTerminator) .

      【讨论】:

      • 谢谢,这适用于我的大多数示例,但我在某些情况下,例如在句子 "shit on shirt" 中找到单词“sh.it”(中间的点)导致匹配“衬衫”,因为点匹配任何东西,我想我需要转义点?
      • 是的,如果您真的要搜索任何字符串,您需要转义 .?+{[( 等.我以为你在找词……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多