Swift: The length of a string. Part 3.

Remember all that fuss about how long a string was? Eventually the consensus settled on countElements. Then Swift changed, so it became count. And now in Swift 2.0, strings aren’t collections any more.

So I spent a lot of time doing this. And for the moment, I’m going with

string.characters.count

to determine how long a typical string is (composed multi-image character strings excepted) and

string == "" // or
string.isEmpty

to check if the string has content. Here are the performance results:

// 1 million iterations, command line compilation

string == ""
Elapsed time: 0.0354770421981812

string.isEmpty
Elapsed time: 0.0294860005378723

string.characters.isEmpty
Elapsed time: 0.33618700504303

Update. Yes, I know I can use Cocoa to calculate the count (as in the following example) but that seems very non-Swift-y and is processor  heavy. For example compare the speed of 1000 trials (not 1 million, just 1 thousand) between characters.count and lengthFromLayout for a  32-character string with embedded emoji:

Elapsed time: 0.00376600027084351

Elapsed time: 0.329634010791779

extension String {
    var lengthFromLayout : Int {
        if isEmpty {return 0}
        let textStorage = NSTextStorage(string:self)
        let layoutmgr = NSLayoutManager(); layoutmgr.textStorage = textStorage
        let container = NSTextContainer(size: CGSizeMake(.max, .max))
        layoutmgr.addTextContainer(container)
        
        var trueCount = 1
        var bounds = layoutmgr.boundingRectForGlyphRange(
            NSMakeRange(0, 1), inTextContainer: container)

        for index in 1..<layoutmgr.numberOfGlyphs {
            let testBounds = layoutmgr.boundingRectForGlyphRange(
                NSMakeRange(index, 1), inTextContainer: container)
            if !CGRectEqualToRect(bounds, testBounds) {
                bounds = testBounds; trueCount++
            }
        }
        return trueCount
    }
}

Comments are closed.