Pat*_*tru 2 unicode line-endings swift
从Web服务中读取一个中等大小的文件(大约500kByte)后,我有一个lines最初编码的常规Swift String().isolatin1.在实际拆分之前,我想计算行数(快速),以便能够初始化进度条.
实现这一目标的最好的Swift成语是什么?
我想出了以下内容:
let linesCount = lines.reduce(into: 0) { (count, letter) in
if letter == "\r\n" {
count += 1
}
}
Run Code Online (Sandbox Code Playgroud)
这看起来并不太糟糕,但我问自己是否有更短/更快的方法.该characters属性提供对一系列Unicode字素的访问,这些字形\r\n仅作为一个实体处理.用all检查这个CharacterSet.newlines不起作用,因为CharacterSet它不是一组Character但Unicode.Scalar在我的书中有一组(在我的书中有点反直觉),它是一组代码点(其中\ r \n计为两个代码点),而不是字形.试
var lines = "Hello, playground\r\nhere too\r\nGalahad\r\n"
lines.unicodeScalars.reduce(into: 0) { (cnt, letter) in
if CharacterSet.newlines.contains(letter) {
cnt += 1
}
Run Code Online (Sandbox Code Playgroud)
}
将计数为6而不是3.因此这比上述方法更通用,但它不能正确用于CRLF行结尾.
有没有办法允许更多的行结束约定(如CharacterSet.newlines)仍然可以实现CRLF的正确结果?可以使用更少的代码计算行数(同时仍然保持可读性)?
如果您可以在NSString上使用Foundation方法,我建议使用
enumerateLines(_ block: @escaping (String, UnsafeMutablePointer<ObjCBool>) -> Void)
Run Code Online (Sandbox Code Playgroud)
这是一个例子:
import Foundation
let base = "Hello, playground\r\nhere too\r\nGalahad\r\n"
let ns = base as NSString
ns.enumerateLines { (str, _) in
print(str)
}
Run Code Online (Sandbox Code Playgroud)
它会正确地分隔线条,同时考虑所有换行类型,例如"\ r \n","\n"等:
你好,
这里的游乐场也是
加拉哈德
在我的例子中,我打印了这些行,但是根据需要计算它们是微不足道的 - 我的版本仅用于演示.
因为我没有找到计算换行符的通用方法,所以我最终只是通过遍历所有字符来解决我的问题
let linesCount = text.reduce(into: 0) { (count, letter) in
if letter == "\r\n" { // This treats CRLF as one "letter", contrary to UnicodeScalars
count += 1
}
}
Run Code Online (Sandbox Code Playgroud)
我确信这比计算行计数要快得多,但我决定最终进行测量.今天我终于到了,发现......我不能再错了.
10000行字符串在大约1.0秒内计算如上所述的行,但是使用枚举计数
var enumCount = 0
text.enumerateLines { (str, _) in
enumCount += 1
}
Run Code Online (Sandbox Code Playgroud)
只花了大约0.8秒,并且持续快了20%多一点.我不知道斯威夫特的工程师躲在他们的衣服里有什么技巧,但他们确实enumerateLines很快就能成功.这只是为了记录.