Start learning free

LESSON 198 OF 415 · STRINGS

Strings in Swift: Indexes, Slices and Character Arrays

Lesson Read the full explanation

The Swift String represents a sequence of characters, each identified by one index.

Creation:

To create strings in Swift, you use double quotes like this:

let greeting = "Hello"

Accessing characters:

To access the characters in a string, you use subscripting with String.Index

The following example returns the first character of a string:

let str = "Hello"
let ch = str[str.startIndex]
// ch is "H"

Getting the length:

We can get the length of a string using the .count property.

To access the last character of the string, you use the last property, which is an optional, so we unwrap it with ! here:

let str = "Hello"
let ch = str.last!
// ch is "o"

Concatenating strings via + operator:

To concatenate two or more strings, you use the + operator:

let name = "John"
let str = "Hello " + name

print(str) // prints "Hello John"

If you want to assemble a string piece by piece, you can use the += operator:

var greet = "Welcome"
let name = "John"
greet += " to AlgoCademy, "
greet += name

print(greet) // "Welcome to AlgoCademy, John"

When concatenating many strings, it is recommended to collect them in an array and use joined() for performance

String slicing

We often want to get a substring of a string. For this, we use index-based subscripting.

Computing a range from startIndex to endIndex and subscripting returns the substring between those positions:

let str = "JavaScript"
let start = str.index(str.startIndex, offsetBy: 2)
let end = str.index(str.startIndex, offsetBy: 6)
let substr = String(str[start..<end])

print(substr) // prints "vaSc"

The start index is the position (here, an offset of 2 from the beginning) at which the extraction starts.

The end index is the position (here, an offset of 6) before which the extraction ends. The substr will not include the character at the end index.

If you want to extract from an index to the end of the string, use an open-ended range:

let str = "JavaScript"
let start = str.index(str.startIndex, offsetBy: 4)
let substr = String(str[start...])

print(substr) // "Script"

String Immutability:

In Swift, String values declared with let are immutable, which means that they cannot be altered once created.

For example, the following code:

let myStr = "Bob"
// myStr[0] = "J" // compile error! String has no integer subscript

cannot change the value of myStr to "Job", because the contents of myStr cannot be altered.

Note that this does not mean that myStr cannot be changed, just that the individual characters of a string literal cannot be changed. The only way to change myStr would be to assign it with a new string, like this:

var myStr = "Bob"
myStr = "Job"
// or
let idx = myStr.index(myStr.startIndex, offsetBy: 1)
myStr = "J" + String(myStr[idx...])

Immutability affects performance when concatenating many strings; it is recommended to collect substrings in an array and use joined() for performance


Convert a string to an array of characters:

When we have to change characters often in a string, we want a way of doing this quickly. Because a character of a string can't be changed by its integer position, we change it by creating a whole new string, which is O(n).

But arrays are mutable and changing an element in an array is O(1). So what we can do is first convert our string to an array of characters, operate on that array and then convert the array back to a string.

We can convert a string to an array of characters using Array() like this:

var str = "Andy"
var myArr = Array(str)

// myArr is ["A", "n", "d", "y"]
myArr[0] = "a"
myArr[2] = "D"

// We convert an array of characters back to a string using String():
str = String(myArr)

print(str) // "anDy"

Iterating through the characters:

We can iterate through the elements of a string using a for-in loop like this:

let myStr = "Andy"
for ch in myStr {
    print(ch)
}

// This will print the characters "A", "n", "d" and "y" on different lines

This takes O(n) time, where n is the length of the string we iterate on.


Assignment
Follow the Coding Tutorial and let's play with some strings.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 7
    Ctrl + Enter to check

    SWIFT · STRINGS

    Strings in Swift, explained

    What this lesson covers

    A Swift String is a sequence of Character values. This lesson shows how to create strings, join them, take parts of them, change them and loop over them. The exercise at the end builds "TypeScript" out of "Java" using most of these tools.

    Creating, measuring and joining

    Strings are written in double quotes. count gives the number of characters, last gives the final character as an optional (it is nil for an empty string), and + joins two strings:

    let str = "Hello"
    print(str.count, str.last!, str[str.startIndex])
    let name = "John"
    var greet = "Welcome"
    greet += " to the course, "
    greet += name
    print(greet)
    
    5 o H
    Welcome to the course, John
    

    The ! after last unwraps the optional and stops the program if it is nil. Use it only when the string cannot be empty. To build a long result from many pieces, collect them in an array and call joined() once.

    Indexing and slicing

    A string cannot be subscripted with an integer. The compiler rejects str[0]. You ask the string for an index with index(_:offsetBy:) and subscript with that:

    let text = "JavaScript"
    let start = text.index(text.startIndex, offsetBy: 2)
    let end = text.index(text.startIndex, offsetBy: 6)
    let substr = String(text[start..<end])
    print(substr)
    print(String(text[text.index(text.startIndex, offsetBy: 4)...]))
    
    vaSc
    Script
    

    The range start..<end stops before end, and start... runs to the end of the string. Subscripting with a range returns a Substring, a view into the original string, so wrap it in String(...) when you want a separate string. An offset beyond the end of the string stops the program with an "index out of bounds" error.

    For the common cases there are shortcuts. dropFirst(4) skips the first four characters, prefix(2) keeps the first two and suffix(3) keeps the last three. They also return substrings.

    Strings are values

    A string held in a let cannot change at all. A string held in a var can be assigned a new value or appended to, but you cannot replace one character in place. To get "Job" from "Bob", build a new string:

    var myStr = "Bob"
    myStr = "J" + String(myStr[myStr.index(after: myStr.startIndex)...])
    print(myStr)
    
    Job
    

    Building a new string copies all the characters, so it costs O(n). If you must change many characters, convert once to an array of characters, edit the array, and convert back:

    var word = "Andy"
    var chars = Array(word)
    chars[0] = "a"
    chars[2] = "D"
    word = String(chars)
    print(word)
    
    anDy
    

    An array element can be changed in O(1), and the two conversions cost O(n) each. Note that the new elements are written in double quotes too: Swift reads "a" as a Character when the array holds characters.

    Looping over a string

    A for-in loop visits each character in order, in O(n) time:

    for ch in "Andy" {
        print(ch)
    }
    
    A
    n
    d
    y
    

    The exercise, step by step

    1. Create lang. Declare it with var and the value "Java", because the next step changes it.
    2. Append. lang += "script" makes it "Javascript".
    3. Take the tail. lang.dropFirst(4) skips "Java" and leaves "script" as a Substring. Wrapping it in String(...) gives the constant substring.
    4. Join. "Type" + substring gives "Typescript" in a var called newLang.
    5. Convert to characters. Array(newLang) gives a [Character] named characters, which can be indexed with integers.
    6. Capitalize. The lowercase s is the fifth character, index 4, so characters[4] = "S".
    7. Convert back. String(characters) is assigned to newLang, which now holds "TypeScript".
    var lang = "Java"
    lang += "script"
    let substring = String(lang.dropFirst(4))
    var newLang = "Type" + substring
    var characters = Array(newLang)
    characters[4] = "S"
    newLang = String(characters)
    

    Printing the variables afterwards shows Javascript, script and TypeScript.

    Common mistakes

    • Using str[0]. It does not compile. Use an index, or Array(str).
    • Joining a Character to a String with +. Write String(ch) first.
    • Forgetting String(...) around a slice. The result is a Substring, which cannot be assigned to a String variable.
    • Off-by-one in offsets. Offsets start at 0, and the end of a ..< range is excluded.

    Key takeaways

    • Strings are collections of Character values; count counts characters.
    • Use String.Index or Array(str) for positions, and String(...) to turn slices and arrays back into strings.
    • Strings are values: changing one means building a new one.
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free