【问题标题】:How to get an array of words from paragraph in Swift?如何从 Swift 中的段落中获取单词数组?
【发布时间】:2015-07-26 02:44:51
【问题描述】:

如果我有一些类似下面的句子,

"Hello everyone. This is a sentence."

如何使用 Swift 获取这样的数组

var words = ["Hello", "everyone", "This", "is", "a", "sentence"]

我还需要一种方法来记住每个单词在原始字符串中的位置,以及句号和逗号的位置。因此,如果我要将这个单词数组重新转换为相同的字符串,它将读取

"Hello everyone. This is a sentence."

谢谢!

【问题讨论】:

  • 没关系,我会把所有的标点符号和它的索引分开存储,然后放回后面/
  • 为什么需要这样做?为什么不能只存储原始字符串?
  • 因为我需要能够操纵单词并用它们做事,然后返回原句。如果单词中包含标点符号,我无法更改它们。
  • 好的,我发布了一个可能的解决方案。

标签: arrays string swift words


【解决方案1】:

按单词分解的子字符串直接内置在 Cocoa 中:

let s = "Hello everyone. This is a sentence."
var arr = [String]()
s.enumerateSubstringsInRange(s.startIndex..<s.endIndex, options: .ByWords) { 
    ss, r, r2, stop in
    arr.append(ss)
}
// now arr is ["Hello", "everyone", "This", "is", "a", "sentence"]

(但是你的规范的其余部分对我来说毫无意义,所以我省略了它。你可以看看如何计算出单词的来源,因为rr2 这两个范围告诉你所有关于它的信息.)

【讨论】:

    【解决方案2】:

    有了这个,您可以以结构化的方式解析句子,这样您就可以修改单词并能够在任何时候重构完整的句子。

    这样做的方法是:

    1. 按顺序在包含单词、标点符号和空格的标记列表中解析句子。

    2. 将每个标记包装在一个“标记”类中,这样可以更方便地访问,具体来说,可以让您快速查询标记是否是一个单词。

    3. 然后,您可以在需要仅包含单词的列表时使用isWord 进行过滤,并对其进行修改。

    4. 修改将反映在令牌数组中。所以当你想再次构造完整的句子时,你只需加入tokens数组即可。

    实施:

    let input = "Hello everyone. This is a sentence."
    
    class Token {
        var text: String
        var isWord: Bool {
            return !(text == " " || text == ".")
        }
        init(text: String) {
            self.text = text
        }
    }
    
    let options: NSLinguisticTaggerOptions = .OmitOther
    let schemes = [NSLinguisticTagSchemeLexicalClass]
    let tagger = NSLinguisticTagger(tagSchemes: schemes, options: Int(options.rawValue))
    let range = NSMakeRange(0, (input as NSString).length)
    tagger.string = input
    var parts : [String] = [] // here we put all the parts including spaces and punctuation signs, such that we can reconstruct sentence at any time
    tagger.enumerateTagsInRange(
        range,
        scheme: NSLinguisticTagSchemeLexicalClass,
        options: options) {
            (tag, tokenRange, _, _) in
    
            let token = (input as NSString).substringWithRange(tokenRange)
            parts.append(token)
    }
    
    println(parts) //"[Hello,  , everyone, .,  , This,  , is,  , a,  , sentence, .]"
    let tokens = parts.map{Token(text: $0)} // wrap the parts in a data structure to handle data more conveniently
    let words = tokens.filter{$0.isWord} // get the tokens with only words, if you need them separatedly.
    words[1].text = "world" // manipulate a word - this will reflect in the stored sentence
    let text = join("", tokens.map{$0.text}) // "Hello world. This is a sentence."
    

    【讨论】:

      【解决方案3】:

      基于@matt 的想法,您可以使用enumerateSubstringsInRange 构建一个数组,还可以在数组中添加标点符号作为单独的项目。然后还创建一个函数,当您开始使用数组时,该函数可以使用字符集确定字符串是否为标点符号。 见下文:

      func checkCharSet(part:String, cSet:NSCharacterSet) -> Bool{
          let check = part.rangeOfCharacterFromSet(cSet)
          return (check != nil) ? true : false
      }
      
      func isPunctuation(part:String) -> Bool{
          let punctSet = NSCharacterSet.punctuationCharacterSet()
          return checkCharSet(part, punctSet)
      }    
      
      func isHexadecimal(part:String) -> Bool{
          let hexadecimal = NSCharacterSet.alphanumericCharacterSet()
          return checkCharSet(part, hexadecimal)
      }
      

      然后利用这两个函数,我们可以相应地构建我们的数组。

      let s = "Hello everyone. This is a sentence."
      
      var arr = [String]()
      var part:String = ""
      
      
      s.enumerateSubstringsInRange(s.startIndex..<s.endIndex, options: .ByComposedCharacterSequences) { (
          ss, r, r2, stop) -> () in
      
          if isHexadecimal(ss){
              part += ss
          }else{
              arr.append(part)
              arr.append(ss)
              part = ""
          }
      }
      

      打印和过滤结果:

      let wordsOnly = arr.filter({isHexadecimal($0)})
      let punctOnly = arr.filter({isPunctuation($0)})
      
      println("\(arr)")
      println("\(wordsOnly)")
      println("\(punctOnly)")
      

      http://www.swiftstub.com/873988306/?v=gm

      【讨论】:

      • 但这并不能解决标点符号的问题。
      • @Michael L 好的,我认为这个解决方案更符合您的需求。
      • @MichaelL 做了一些小的改动,因为我想到节省数组中的空间也是必要的..
      【解决方案4】:

      @Ixx,我不认为你的 Token 类很有用。以下是我要做的修改:

      import Cocoa
      
      let input = "Hello everyone. This is a sentence."
      
      let options: NSLinguisticTaggerOptions = .OmitOther
      let schemes = [NSLinguisticTagSchemeTokenType]
      let tagger = NSLinguisticTagger(tagSchemes: schemes, options: Int(options.rawValue))
      
      let range = NSMakeRange(0, (input as NSString).length)
      tagger.string = input
      
      var parts: [String] = [] // here we put all the parts including spaces and punctuation signs, such that we can reconstruct sentence at any time
      var words: [String] = []
      
      tagger.enumerateTagsInRange(
          range,
          scheme: NSLinguisticTagSchemeTokenType,
          options: options) {
      
          (tag, tokenRange, _, _) in
      
              let part = (input as NSString).substringWithRange(tokenRange)
              parts.append(part)
      
              if tag == "Word" {
                  words.append(part)
              }
      }
      
      
      println(parts) 
      println(words)
      
      --output:--
      [Hello,  , everyone, .,  , This,  , is,  , a,  , sentence, .]
      [Hello, everyone, This, is, a, sentence]
      

      或者,为了获得最大的灵活性,您可以将 tokenType 添加到 Token 类并使用 tokenType 属性过滤令牌数组。对于 schemeNSLinguisticTagSchemeTokenType,标记类型是 Word、标点符号、空格或其他——这是 op 需要了解的唯一标记类型。

      class Token {
          var text: String
          var tokenType: String
      
          init(text: String, tokenType: String) {
              self.text = text
              self.tokenType = tokenType
          }
      }
      
      let input = "Hello everyone. This is a sentence."
      
      let options: NSLinguisticTaggerOptions = .OmitOther
      let schemes = [NSLinguisticTagSchemeTokenType]
      let tagger = NSLinguisticTagger(tagSchemes: schemes, options: Int(options.rawValue))
      
      let range = NSMakeRange(0, (input as NSString).length)
      tagger.string = input
      
      var parts: [String] = [] // here we put all the parts including spaces and punctuation signs, such that we can reconstruct sentence at any time
      //var words: [String] = []
      var tokens: [Token] = []
      
      tagger.enumerateTagsInRange(
          range,
          scheme: NSLinguisticTagSchemeTokenType,
          options: options) {
      
          (tag, tokenRange, _, _) in
      
              let part = (input as NSString).substringWithRange(tokenRange)
              parts.append(part)
      
              tokens.append(
                  Token(text: part, tokenType: tag)
              )
      }
      
      
      println(parts) //"[Hello,  , everyone, .,  , This,  , is,  , a,  , sentence, .]"
      
      let words = tokens.filter({$0.tokenType == "Word"})
      
      println(
          words.map({$0.text}  //[Hello, everyone, This, is, a, sentence]
      )
      

      【讨论】:

      • 这应该是一条评论。您正在复制我的整个答案,只是为了进行较小的便利性改进。我没有考虑这么多,因为甚至不清楚 TO 需要什么以及这种方法是否可用。如果您将其添加为评论,很高兴改进我的答案 - 代码可以发布,例如在swiftstub.com
      • @Ixx:你知道,我是为你的帖子点赞的人。我只是想帮助操作员。 这应该是注释。--注释中的代码将无法阅读。
      • 我不想过分生气,复制答案以进行相当小的改进只是一种不好的礼仪。从逻辑上讲,TO 会选择你的答案,因为它是一个改进的版本,而忽略了最初的想法和工作在我手中的事实。感谢您的支持,但重点是...关于代码,这就是为什么我建议使用 swiftstub.com 之类的外部站点
      猜你喜欢
      • 1970-01-01
      • 2020-09-30
      • 1970-01-01
      • 2020-01-28
      • 2020-06-17
      • 2020-08-18
      • 1970-01-01
      • 2021-09-11
      • 1970-01-01
      相关资源
      最近更新 更多