【问题标题】:Split text into array while maintaining the punctuation in Swift将文本拆分为数组,同时保持 Swift 中的标点符号
【发布时间】:2017-02-11 14:17:48
【问题描述】:

我想将文本拆分成一个数组,保持标点符号与其余单词分开,所以字符串如下:

Hello, I am Albert Einstein.

应该变成这样的数组:

["Hello", ",", "I", "am", "Albert", "Einstein", "."]

我试过sting.components(separatedBy: CharacterSet.init(charactersIn: " ,;;:")),但是这个方法会删除所有的标点符号,并返回一个这样的数组:

["Hello", "I", "am", "Albert", "Einstein"]

那么,我怎样才能得到一个像我的第一个例子一样的数组呢?

【问题讨论】:

  • 您是否尝试过通过正则表达式将其拆分然后合并组?即如果你运行类似([A-Za-z\']*)([,\.])* 的东西,那么[0, 1] 的可选子组将包含你的部分(例如'Hello',','),然后你可以在所有非零组上运行一个flatMap将它们合并成一个单独的字符串数组
  • 不,你能在答案中解释得更好吗? @Guardanis
  • 我很困惑您想要的结果输出是什么?您能否也将其添加到您的问题中
  • 我已经更新了@Honey 的问题

标签: ios arrays swift string split


【解决方案1】:

它作为解决方案并不漂亮,但您可以尝试:

var str = "Hello, I am Albert Einstein."
var list = [String]()
var currentSubString = "";
//enumerate to get all characters including ".", ",", ";", " "
str.enumerateSubstrings(in: str.startIndex..<str.endIndex, options: String.EnumerationOptions.byComposedCharacterSequences) { (substring, substringRange, enclosingRange, value) in
    if let _subString = substring {
        if (!currentSubString.isEmpty &&
            (_subString.compare(" ") == .orderedSame
                || _subString.compare(",") == .orderedSame
                || _subString.compare(".") == .orderedSame
                || _subString.compare(";") == .orderedSame
            )
            ) {
            //create word if see any of those character and currentSubString is not empty
            list.append(currentSubString)
            currentSubString = _subString.trimmingCharacters(in: CharacterSet.whitespaces )
        } else {
            //add to current sub string if current character is not space.
            if (_subString.compare(" ") != .orderedSame) {
                currentSubString += _subString
            }
        }
    }
}


//last word
if (!currentSubString.isEmpty) {
    list.append(currentSubString)
}

在 Swift3 中:

var str = "Hello, I am Albert Einstein."
var list = [String]()
var currentSubString = "";
//enumerate to get all characters including ".", ",", ";", " "
str.enumerateSubstrings(in: str.startIndex..<str.endIndex, options: String.EnumerationOptions.byComposedCharacterSequences) { (substring, substringRange, enclosingRange, value) in
    if let _subString = substring {
        if (!currentSubString.isEmpty &&
            (_subString.compare(" ") == .orderedSame
                || _subString.compare(",") == .orderedSame
                || _subString.compare(".") == .orderedSame
                || _subString.compare(";") == .orderedSame
            )
            ) {
            //create word if see any of those character and currentSubString is not empty
            list.append(currentSubString)
            currentSubString = _subString.trimmingCharacters(in: CharacterSet.whitespaces )
        } else {
            //add to current sub string if current character is not space.
            if (_subString.compare(" ") != .orderedSame) {
                currentSubString += _subString
            }
        }
    }
} 


//last word
if (!currentSubString.isEmpty) {
    list.append(currentSubString)
}

这个想法是循环所有字符并同时创建单词。单词是一组连续的字符,不是,.;。因此,在循环中创建单词的过程中,如果我们看到其中一个字符,我们就完成了当前单词,并且当前正在构造的单词不为空。 使用您的输入分解步骤:

  1. 获取H(不是空格也不是其他终端字符) -> currentSubString = "H"
  2. 获取e(不是空格也不是其他终端字符) -> currentSubString = "他"
  3. 获取l(不是空格也不是其他终端字符) -> currentSubString = "Hel"
  4. 获取l(不是空格也不是其他终端字符) -> currentSubString = "地狱"
  5. 获取o(不是空格也不是其他终端字符) -> currentSubString = "你好"
  6. 得到.(是终端字符)
    • ->由于currentSubString不为空,添加到list并重新构建下一个单词,然后list = [“Hello”]
    • -> currentSubString = "." (我使用修剪的原因只是如果我得到这个字符就删除。但是对于其他终端字符,我们必须保留下一个单词。
  7. 获取(是空格字符)
    • ->由于currentSubString不为空,添加list并重新构建-> list = ["Hello", "."]
    • -> currentSubString = ""(已修整)。 ...等等。

【讨论】:

  • 我不明白一些代码行,但它有效!谢谢!
  • Ehmm...整个if语句@Hoa
  • 最后看我的评论。也许对你来说更清楚:)
【解决方案2】:

从我的评论中解释...将regular expressions 视为一种在字符串中很好地找到模式的方法。在您的情况下,模式是单词(字母组)与其他可能的符号(标点符号)之间。

在我的评论中使用正则表达式(我在这里稍微扩展了一下),例如:([,\.\:\"])*([A-Za-z0-9\']*)([,\.\:\"])*

在那里,我们有 3 个groups。第一个搜索任何符号(例如前导引号)。第二个是搜索字母、数字和撇号(因为人们喜欢连接单词,比如“I'm”)。第三组搜索任何尾随标点符号。

编辑注意:上面的组用括号 ( 和 ) 表示,而 [ 和 ] 括号表示搜索可接受的字符。因此,例如,[A-Z] 表示 A-Z 中的所有大写字母都是可以接受的。 [A-Za-z] 让您可以同时获得上下,而[A-Za-z0-9] 包括从 0 到 9 的所有字母和数字。当然,写这篇文章有速记版本,但你会在路上发现。

所以现在我们有了一种方法来分隔所有的单词和标点符号,现在你需要实际使用它,按照以下方式做一些事情:

func find(value: NSString) throws -> [NSString] {
    let regex = try NSRegularExpression(pattern: "([,\\.\\:\\\"])*([A-Za-z0-9\\']*)([,\\.\\:\\\"])*") // Notice you have to escape the values in code
    let results = regex.matches(in: value, range: NSRange(location: 0, length: nsString.length))
    return results.map({ value.substring(with: $0.range) }).filter({ $0 != nil })
}

这应该会给你在你提供给方法的字符串值中找到的每个非零组。

当然,最后一个过滤方法可能不是必需的,但我对 Swift 如何处理正则表达式还不够熟悉,无法确定。

但这绝对应该为您指明正确的方向......

干杯~

【讨论】:

  • 某些事情没有按预期工作:["Hello,", "playground", "I", "am", "Alessio."]
  • 是的,看起来 swift 会自动将它们分组在一起,而不是为您提供子组的范围。给我一点时间来尝试找到可以帮助您深入了解子组的资源
  • 对不起,我发的链接是JS。 This is a Swift example 获取单独的捕获组
  • @OttavioCocci 我对正则表达式也不太了解,但我有时会从 2 个站点使用。请参阅herehere。它们是您可以使用的很棒的教程和正则表达式验证器工具。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-19
  • 1970-01-01
  • 2011-07-10
  • 2012-01-22
  • 2020-05-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多