在Swift 3中,您可以使用{<1}}计算字符:
String
我需要经常这样做,上面那行看起来可能是O(N)。有没有办法获得一个字符串长度,或某些的长度 - 可能是底层的unicode缓冲区 - 一个操作,保证不必走遍整个字符串?也许:
str.characters.count
我问,因为我每次用户输入一个字符时都会查看某些文字的长度,以限制str.utf16.count
的大小。调用不需要是字形的精确计数,例如UITextView
。
答案 0 :(得分:4)
这是一个很好的问题。答案是......复杂的。从UTF-8转换为UTF-16,反之亦然,或转换为或从其他编码转换,都需要检查字符串,因为字符可以由多个代码单元组成。因此,如果您希望在不变的时间内获得计数,那么它将归结为内部表示的内容。如果字符串在内部使用UTF-16,那么它是一个合理的假设string.utf16.count
将处于恒定时间,但如果内部表示是UTF-8或其他东西,那么字符串将需要是分析以确定UTF-16的长度。那么内部使用的字符串是什么?良好:
https://github.com/apple/swift/blob/master/stdlib/public/core/StringCore.swift
/// The core implementation of a highly-optimizable String that
/// can store both ASCII and UTF-16, and can wrap native Swift
/// _StringBuffer or NSString instances.
这令人沮丧。内部表示可以是ASCII 或 UTF-16,或它可以包装基金会NSString
。人力资源管理。我们知道NSString
在内部使用UTF-16,因为这是actually documented,所以这很好。所以这里的主要异常值是字符串存储ASCII时。节省的优点是,由于前128个Unicode代码点与ASCII字符集具有相同的值,因此任何ASCII字符0xXX
都应对应于UTF-16字符0x00XX
,因此UTF-16长度应该只是ASCII长度乘以2,因此可以在恒定时间内计算。这是实施中的情况吗?我们来看看。
在the UTF16View
source中,没有count
的实施。看来count
继承自Collection
's implementation,通过distance()
实施:
public var count: IndexDistance {
return distance(from: startIndex, to: endIndex)
}
UTF16View
's implementation of distance()
看起来像这样:
public func distance(from start: Index, to end: Index) -> IndexDistance {
// FIXME: swift-3-indexing-model: range check start and end?
return start.encodedOffset.distance(to: end.encodedOffset)
}
在the String.Index
source中,encodedOffset
看起来像这样:
public var encodedOffset : Int {
return Int(_compoundOffset >> _Self._strideBits)
}
其中_compoundOffset
似乎是一个简单的64位整数:
internal var _compoundOffset : UInt64
和_strideBits
似乎也是一个直的整数:
internal static var _strideBits : Int { return 2 }
所以......看起来......就像你应该从string.utf16.count
获得恒定的时间,因为除非我在某个地方犯了错误,否则你只需要移位几个整数然后比较结果(我可能仍然会进行一些测试以确定)。当然,需要注意的是,这没有记录,因此可能会在未来发生变化 - 特别是因为documentation for String
确实声称它需要遍历字符串:
与isEmpty不同,计算视图的count属性需要遍历字符串的元素。
尽管如此,您还是使用了UITextView
,这是通过NSAttributedString
在Objective-C中实现的。如果您愿意承担Objective-C消息传递开销(诚实地说,可能是在场景下发生的,以生成String
),您可以调用它length
属性,NSAttributedString
构建于NSString
之上, 保证内部使用UTF-16,几乎可以肯定是恒定的时间。