如何在Swift中用新行拆分字符串

Sur*_*gch 34 arrays string newline swift

我有一个从文本文件中获取的字符串.

文本文件:

Line 1
Line 2
Line 3
...
Run Code Online (Sandbox Code Playgroud)

我想将它转换为数组,每行一个数组元素.

[ "Line 1", "Line 2", "Line 3", ... ]
Run Code Online (Sandbox Code Playgroud)

根据文件的保存方式,字符串可以采用以下形式之一:

  • string = "Line 1\nLine 2\nLine 3\n..."\n新行(换行)字符在哪里

  • string = "Line 1\r\nLine 2\r\nLine 3\r\n..."\r回车符在哪里.

据我所知,它\n现在常用于Apple/Linux,而\r\n在Windows中使用.

如何在任何换行符处拆分字符串以获取没有任何空元素的String数组?

更新

有几种解决方案可以在下面使用.在这一点上,我没有任何令人信服的理由选择一个比其他更正确.可能影响选择的一些因素可能是(1)"Swift"如何以及(2)对于非常长的字符串有多快.您可以通过提升其中一个或多个和/或发表评论来提供反馈.

在这里查看我的总结答案

Leo*_*bus 54

您可以使用String方法enumerateLines:

枚举字符串中的所有行.

Swift 3或更高版本

let sentence = "Line 1\nLine 2\nLine 3\n"
var lines = sentence.split { $0.isNewline }
print(lines)   // "[Line 1, Line 2, Line 3]"
Run Code Online (Sandbox Code Playgroud)
let sentence = "Line 1\nLine 2\nLine 3\n"
var lines: [String] = []
sentence.enumerateLines { line, _ in
    lines.append(line)
}
print(lines)   // "[Line 1, Line 2, Line 3]"
Run Code Online (Sandbox Code Playgroud)

用法:

extension String {
    var lines: [String] {
        var result: [String] = []
        enumerateLines { line, _ in result.append(line) }
        return result
    }
}
Run Code Online (Sandbox Code Playgroud)


zag*_*r 20

Xcode 8.2中,Swift 3.0.1:

使用NSString方法组件(separateBy :)

let text = "line1\nline2"
let array = text.components(separatedBy: CharacterSet.newlines)
Run Code Online (Sandbox Code Playgroud)

或者使用String方法enumerateLines,就像Leo Dabus回答一样

  • 虽然`let array = text.components(separatedBy:.newlines)`看起来干净利落,但实际上它会拆分CRLF行终止符(`\ r \n`)**TWICE**,导致空行. (6认同)
  • `let array = text.components(separatedBy:.newlines)` (2认同)

Stu*_*art 9

在Swift 2中,顶级split函数现在是一个方法CollectionType(每个String"字符视图"符合).该方法有两个版本,您希望将闭包作为谓词来指示是否应将给定元素视为分隔符.

您可以使用字符串中的字符集作为UTF16字符的集合string.utf16,使它们与NSCharacterSetAPI 兼容.这样,我们可以在闭包内部轻松检查字符串中的给定字符是否是换行符字符集的成员.

值得注意的是,split(_:)它将返回一个SubSequence字符(基本上是一个Slice),因此它需要转换回一个字符串数组,这通常更有用.我已经在下面使用了flatMap(String.init)- UTF16View初始化器String是可用的,因此使用flatMap将忽略nil可能返回的任何值,确保返回一个非可选字符串数组.

所以对于一个很好的类似Swift的方式:

let str = "Line 1\nLine 2\r\nLine 3\n"
let newlineChars = NSCharacterSet.newlineCharacterSet()
let lines = str.utf16.split { newlineChars.characterIsMember($0) }.flatMap(String.init)
// lines = ["Line 1", "Line 2", "Line 3"]
Run Code Online (Sandbox Code Playgroud)

这很好的是该split方法有一个参数allowEmptySubsequences,可以确保您不会在结果中收到任何空字符序列.这是false默认情况下,因此您实际上根本不需要指定它.

编辑

如果你想NSCharacterSet完全避免,你可以轻松地分割符合unicode的集合Character.

let lines = str.characters.split { $0 == "\n" || $0 == "\r\n" }.map(String.init)
Run Code Online (Sandbox Code Playgroud)

Swift能够将其"\r\n"视为单个扩展字形集群,将其作为单个集合Character用于比较而不是创建String.另请注意,从a创建字符串的初始化程序Character是不可用的,因此我们可以使用map.


use*_*734 6

let test1 = "Line1\n\rLine2\nLine3\rLine4"
let t1 = test1.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
let t2 = t1.filter{ $0 != "" }
let t3 = t1.filter{ !$0.isEmpty }
Run Code Online (Sandbox Code Playgroud)


Sur*_*gch 6

这个答案是对已经给出的其他解决方案的总结.它来自我更全面的答案,但在这里提供实际的方法选择会很有用.

新行通常使用\n字符进行,但也可以使用\r\n(来自Windows中保存的文件).

解决方案

1. componentsSeparatedByCharactersInSet

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let newlineChars = NSCharacterSet.newlineCharacterSet()
let lineArray = multiLineString.componentsSeparatedByCharactersInSet(newlineChars).filter{!$0.isEmpty}
// "[Line 1, Line 2, Line 3]"
Run Code Online (Sandbox Code Playgroud)

如果filter没有使用,\r\n则会生成一个空数组元素,因为它被计为两个字符,因此在同一位置将字符串分隔两次.

2. split

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let newlineChars = NSCharacterSet.newlineCharacterSet()
let lineArray = multiLineString.utf16.split { newlineChars.characterIsMember($0) }.flatMap(String.init)
// "[Line 1, Line 2, Line 3]"
Run Code Online (Sandbox Code Playgroud)

要么

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let lineArray = multiLineString.characters.split { $0 == "\n" || $0 == "\r\n" }.map(String.init)
// "[Line 1, Line 2, Line 3]"
Run Code Online (Sandbox Code Playgroud)

这里\r\n被视为单个Swift字符(扩展字形集群)

3. enumerateLines

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
var lineArray = [String]()
multiLineString.enumerateLines { (line, stop) -> () in
    lineArray.append(line)
}
// "[Line 1, Line 2, Line 3]"
Run Code Online (Sandbox Code Playgroud)

有关enumerateLine语法的更多信息,请参阅此答案.

笔记:

  • 一个多行字符串通常不会混合两者\r\n,\n但我这样做是为了表明这些方法可以处理这两种格式.
  • NSCharacterSet.newlineCharacterSet()是换行符,定义为(U + 000A-U + 000D,U + 0085),包括\r\n.
  • 这个答案总结了我上一个问题的答案.阅读这些答案以获取更多细节.