【问题标题】:componentsseparatedbystring by multiple separators in Swiftcomponentsseparatedbystring 在 Swift 中由多个分隔符分隔
【发布时间】:2015-12-13 02:17:37
【问题描述】:

所以这里是字符串s

"Hi! How are you? I'm fine. It is 6 p.m. Thank you! That's it."

我希望将它们分成一个数组:

["Hi", "How are you", "I'm fine", "It is 6 p.m", "Thank you", "That's it"]

这意味着分隔符应该是". " + "? " + "! "

我试过了:

let charSet = NSCharacterSet(charactersInString: ".?!")
let array = s.componentsSeparatedByCharactersInSet(charSet)

但它也会将p.m. 分成两个元素。结果:

["Hi", " How are you", " I'm fine", " It is 6 p", "m", " Thank you", " That's it"]

我也试过了

let array = s.componentsSeparatedByString(". ")

它可以很好地分离". ",但如果我也想分离"? ""! ",它就会变得混乱。

那么我有什么办法吗?谢谢!

【问题讨论】:

  • 简单的方法是使用componentsSeparatedByString,但还是会失败。因为不是每个句子都以空格结尾。
  • @RMenke 我试过let array = s.componentsSeparatedByString(". ") 它适用于分离". ",但如果我也想分离"? ""! ",它会变得混乱。
  • 我知道,把我的评论读到最后;)
  • @RMenke 只是忽略字符串中不以空格结尾的最后一句。我怎样才能把前面的句子分开? :)

标签: ios swift split string-split


【解决方案1】:

提供了一种方法,可以让您枚举字符串。您可以通过单词或句子或其他选项来做到这一点。不需要正则表达式。

let s = "Hi! How are you? I'm fine. It is 6 p.m. Thank you! That's it."
var sentences = [String]()
s.enumerateSubstringsInRange(s.startIndex..<s.endIndex, options: .BySentences) { 
    substring, substringRange, enclosingRange, stop in
    sentences.append(substring!)
}
print(sentences)

结果是:

[“嗨!”、“你好吗?”、“我很好。”、“现在是下午 6 点”、“谢谢!”、“就这样。”]

【讨论】:

  • 那么BySentences是系统本身包含的功能吗?
  • 是的。请参阅NSString enumerateSubstringsInRange:options:usingBlock: 的文档。
【解决方案2】:

rmaddy 的回答是正确的 (+1)。 Swift 3 的实现是:

var sentences = [String]()

string.enumerateSubstrings(in: string.startIndex ..< string.endIndex, options: .bySentences) { substring, substringRange, enclosingRange, stop in
    sentences.append(substring!)
}

您也可以使用正则表达式 NSRegularExpression,尽管它比 rmaddy 的 .bySentences 解决方案要复杂得多。在 Swift 3 中:

var sentences = [String]()

let regex = try! NSRegularExpression(pattern: "(^|\\s+)(\\w.*?[.!?]+)(?=(\\s+|$))")
regex.enumerateMatches(in: string, range: NSMakeRange(0, string.characters.count)) { match, flags, stop in
    sentences.append((string as NSString).substring(with: match!.rangeAt(2)))
}

或 Swift 2:

let regex = try! NSRegularExpression(pattern: "(^|\\s+)(\\w.*?[.!?]+)(?=(\\s+|$))", options: [])
var sentences = [String]()
regex.enumerateMatchesInString(string, options: [], range: NSMakeRange(0, string.characters.count)) { match, flags, stop in
    sentences.append((string as NSString).substringWithRange(match!.rangeAtIndex(2)))
}

[.!?] 语法匹配这三个字符中的任何一个。 | 表示“或”。 ^ 匹配字符串的开头。 $ 匹配字符串的结尾。 \\s 匹配空白字符。 \\w 匹配“单词”字符。 * 匹配零个或多个前面的字符。 + 匹配前面的一个或多个字符。 (?=) 是一个前瞻断言(例如,看看那里是否有东西,但不要通过那场比赛)。

我试着简化了一点,但它仍然很复杂。正则表达式提供富文本模式匹配,但不可否认,当您第一次使用它时它有点密集。但是这种翻译也匹配 (a) 重复的标点符号(例如 "Thank you!!!")、(b) 前导空格和 (c) 尾随空格。

【讨论】:

    【解决方案3】:

    如果拆分基础比句子更深奥,这个扩展可以工作。

    extension String {
        public func components(separatedBy separators: [String]) -> [String] {
            var output: [String] = [self]
            for separator in separators {
                output = output.flatMap { $0.components(separatedBy: separator) }
            }
            return output.map { $0.trimmingCharacters(in: .whitespaces)}
        }
    }
    
    let artists = "Rihanna, featuring Calvin Harris".components(separated by: [", with", ", featuring"])
    

    【讨论】:

    • 这是一个非常好的解决方案!但我只需要每组字符的第一次出现。有没有可能实现?
    【解决方案4】:

    我也试图找到一个正则表达式来解决这个问题:(([^.!?]+\s)*\S+(\.|!|\?)) 这里是regexperexample 的解释

    【讨论】:

      【解决方案5】:

      我也从here 找到了一个正则表达式

      var pattern = "(?<=[.?!;…])\\s+(?=[\\p{Lu}\\p{N}])"
      
      let s = "Hi! How are you? I'm fine. It is 6 p.m. Thank you! That's it."
      
      let sReplaced = s.stringByReplacingOccurrencesOfString(pattern, withString:"[*-SENTENCE-*]" as String, options:NSStringCompareOptions.RegularExpressionSearch, range:nil)
      
      let array = sReplaced.componentsSeparatedByString("[*-SENTENCE-*]")
      

      也许这不是一个好方法,因为它必须先替换然后分隔字符串。 :)

      更新:

      对于正则表达式部分,如果您还想匹配中日标点符号(每个标点符号后的空格不是必需的),您可以使用以下一个:

      ((?<=[.?!;…])\\s+|(?<=[。!?;…])\\s*)(?=[\\p{L}\\p{N}])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-08
        • 2010-11-18
        • 1970-01-01
        • 2020-08-22
        • 1970-01-01
        • 1970-01-01
        • 2013-06-07
        相关资源
        最近更新 更多