Dealing with strings in Swift

One of the first weird things you might notice when you start to code in Swift is the new way to manipulate strings. There isn’t an [NSString class] anymore… oh, my!

So, how can we deal with strings? First thing first: what is a string in Swift? As the Apple says:

A string is a series of characters, such as "hello, world" or "albatross". Swift strings are represented by the String type. The contents of a String can be accessed in various ways, including as a collection of Character values.

String as a type!! A type like in many other programming languages? Ok, I can live with this :stuck_out_tongue_winking_eye:.

Anyway, Apple has bridged Swift’s String type with Foundation’s NSString class. That means if you import the Foundation framework in your Swift project you can use the entire NSString API on any String value you create. Also, you can use the String type in calls to any API that requires NSString parameters.

Regardless, managing strings in Swift still seems strange at first. As an example, you can consider the case when you need to know a string length. In old Objective-C you type something like:

NSString *myString = @"Swift rocks!";
int myStringLen = [string length];

But in Swift, you don’t have a method length for the new String type. As I quote above the new String type ‘can be accessed as a collection of Character values’. Then we can get the string length like this:

let myString = "Swift rocks!"
let myStringLen = string.characters.count

Cool, right? Let’s go deep in this ‘characters’ thing.

Working with Characters

Like in other programming languages, we can use subscripting syntax to access every single character in a String value. To do this, we must use the String.Index type associated with our String value.

Why not using a simple integer as the index? Well, as you possibly know, Swift allows us to use Unicode characters in our strings. Actually, Swift’s String and Character types are fully Unicode-compliant. For example, these two strings are equivalent:

// String literal
let myString = "The octocat! :octocat:"

// String from a characters array
let stringFromCharacters : [Character] = [ "T", "h", "e", " ", "o", "c", "t", "o", "c", "a", "t", "!", ":octocat:" ]

In fact, “Swift’s native String type is built from Unicode scalar values. A Unicode scalar is a unique 21-bit number for a character or modifier”. This means that different Unicode characters can require a different quantity of memory to store, so in order to determine which Character is at a given position, you need to iterate over each Unicode scalar from the start or end of that String. For this reason, Swift strings cannot be indexed by integer values.

That’s why String.Index has a bunch of useful properties and methods:

let myString = "The octocat! :octocat:"

let firstChar = myString[myString.startIndex]
// T

let lastChar = myString[myString.endIndex.predecessor()]
// :octocat:

let secondChar = myString[myString.startIndex.successor()]
// h

let tenthChar = myString[myString.startIndex.advancedBy(9)]
// a

myString[myString.endIndex] // error!!

myString[myString.endIndex.successor()] // error!!

Obviously, if you try to access a Character at an index beyond the string’s range limits you get a runtime error, like in the last two sentences.

And the characters property has an indices property that can be used to create a Range of all of the characters indexes in a string:

for index in myString.characters.indices {
    print("\(myString[index]) ", terminator: "")
}
// prints "T h e   o c t o c a t !   :octocat:"

When you understand how Swift’s strings works you can make fun code. As an example I’ve made a new Swift String extension with a bunch of useful methods to deal with strings:

let charsToTrim: [Character] = ["\n", "\r", "\t", " "]

extension String {

    // Simple length shortcut:.
    // Usage: "This is a string".length
    var length: Int {
        return characters.count
    }

    // TRIMMING strings
    // LEFT trim
    // Usage: "  <- these spaces will be trimmed!".trimLeft()
    func trimLeft() -> String {
        if self.isEmpty {
            return ""
        }
        var index = startIndex
        while index < endIndex {
            let char = self[index]
            if (charsToTrim.indexOf(char) == nil) {
                break
            }
            index = index.successor()
        }
        return self[index..<endIndex]
    }

    // RIGHT trim
    // Usage: "Final spaces will be trimmed!    ".trimLeft()
    func trimRight() -> String {
        if self.isEmpty {
            return ""
        }
        var index = endIndex
        while index >= startIndex {
            index = index.predecessor()
            let char = self[index]
            if (charsToTrim.indexOf(char) == nil) {
                break
            }
        }
        return self[startIndex...index]
    }

    // BOTH SIDES trim
    // Usage: "  All side spaces will be trimmed!  ".trim()
    func trim() -> String {
        return self.trimLeft().self.trimRight()
    }

The trim functions can be implemented using [NSString class] bridged through the Foundation framework. For example you can use stringByTrimmingCharactersInSet() to trim a string.

Hope this helps someone. “Tor Dif smusma je” 🖖.

"Dealing with strings in Swift" was originally published on 13 Jan 2016