Swift Strings

Work with text in Swift: string interpolation, counting and looping over characters, common methods, prefixes and suffixes, splitting and joining, and multi-line strings.

Lesson 4 of 43Beginner18 min read

Text appears everywhere in apps: names, messages, search terms, labels on buttons. In Swift, text is a String, written in double quotes, and a String is made up of Characters.

Swift's strings are carefully designed to handle every language correctly. An emoji or an accented letter like "é" counts as one character, just as a reader would expect, even though it's stored as several bytes. The trade-off is that you can't grab the fifth character with text[4] as in some languages; instead Swift gives you safe tools such as prefix, suffix, first and dropFirst.

In this lesson you'll build text with string interpolation, count and loop over characters, use the most common string methods, split and join text, trim spaces, and write multi-line strings. Strings are value types: methods like uppercased() return a new string and leave the original unchanged.

String interpolation

Swift
let name = "Sam"
let items = 3
print("Hi \(name), you have \(items) items")
print("Next year you'll be \(age + 1)")
  • Write \( then any value or expression, then ) inside a string, and Swift inserts its value.
  • Numbers, Bools and other types are converted to text automatically.
  • You can also join strings with +, but interpolation is clearer and doesn't need conversions.
  • Special characters use a backslash: \n for a new line, \" for a quote, \\ for a backslash.

Characters, counting and looping

  • text.count is the number of characters; text.isEmpty checks for "".
  • text.first and text.last are optional Characters (nil for an empty string).
  • text.prefix(3) and text.suffix(3) give the first and last three characters; dropFirst() and dropLast() remove some from the ends.
  • for ch in text { } loops over every character.
  • text.reversed() gives the characters backwards; wrap it in String(...) to get a String.

Results like prefix are a Substring, a lightweight view into the original string. Convert with String(sub) when you store it or pass it to code that expects a String.

Common string methods

MethodExampleResult
uppercased() / lowercased()"Swift".uppercased()"SWIFT"
capitalized (Foundation)"ada lovelace".capitalized"Ada Lovelace"
hasPrefix(x) / hasSuffix(x)"photo.png".hasSuffix(".png")true
contains(x)"swift".contains("if")true
replacingOccurrences(of:with:) (Foundation)"a-b".replacingOccurrences(of: "-", with: "/")"a/b"
trimmingCharacters(in: .whitespaces) (Foundation)" hi ".trimming..."hi"

Methods marked Foundation need import Foundation at the top of the file. In an app, SwiftUI and UIKit import it for you.

Splitting, joining and multi-line strings

split(separator: ",") breaks a string into an array of Substrings, and joined(separator: ", ") joins an array of strings back together:

Swift
let tags = "swift,ios,xcode".split(separator: ",")
print(tags.joined(separator: " | "))   // swift | ios | xcode

A multi-line string starts and ends with three double quotes on their own lines. Indentation before the closing quotes is removed from every line, so you can keep code tidy:

Swift
let email = """
    Dear \(name),
    Your order has shipped.
    """

String indexes and why text[2] is not allowed

Characters in Swift can take different amounts of memory. A plain "e" is one byte in UTF-8, "é" is two, and a flag emoji is eight, yet each counts as one Character:

Swift
let word = "café"
print(word.count, word.utf8.count)      // 4 5

Because of this, Swift can't jump straight to "character number 2"; it has to walk through the string from the start. Rather than hide that cost behind text[2], Swift makes you ask for a position explicitly with a String.Index:

Swift
let text = "Swift"
let i = text.index(text.startIndex, offsetBy: 2)
print(text[i])                             // i
if let f = text.firstIndex(of: "f") {
    print(text[..<f])                      // Swi
}

In practice you rarely need indexes. prefix, suffix, first, contains and split cover most everyday jobs. If you find yourself indexing heavily, converting to an array with Array(text) gives you integer positions at the cost of a copy.

Comparing, sorting and raw strings

< and > compare strings character by character, using Unicode values. All capital letters come before all lower-case ones, so "Zebra" < "apple" is true. To sort the way people expect, compare lower-cased copies:

Swift
let fruit = ["pear", "Apple", "banana"]
print(fruit.sorted { $0.lowercased() < $1.lowercased() })
// ["Apple", "banana", "pear"]

A raw string is wrapped in #" and "#. Backslashes and quotes inside it are taken literally, which is handy for file paths and regular expressions. Interpolation still works if you add the hash: #"Total: \#(n)"#.

Swift Strings Syntax

String essentials

let s = "Hello, \(name)! You are \(age + 1) next year."
s.count   s.isEmpty   s.first   s.prefix(5)   s.suffix(3)
s.uppercased()   s.hasPrefix("He")   s.contains("lo")
let parts = s.split(separator: " ")
["a", "b"].joined(separator: ", ")
String(s.reversed())
let block = """
    Line one
    Line two
    """

Swift Strings Summary

  • Strings use double quotes; \(value) inserts values into them.
  • count, isEmpty, first, last, prefix, suffix and for-in work with characters.
  • Swift strings don't use integer indexes, because characters can vary in size.
  • uppercased, hasPrefix, contains, split and joined are common methods; some need Foundation.
  • Triple quotes make multi-line strings; == compares text.

Swift Strings Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Interpolation and string methods

Swift
let first = "ada"
let last = "Lovelace"
let full = "\(first.prefix(1).uppercased())\(first.dropFirst()) \(last)"

print(full)
print("\(full.count) characters")
print(full.uppercased())
print(full.hasPrefix("Ada"), full.contains("love"))
Output
Ada Lovelace
12 characters
ADA LOVELACE
true false
Line-by-line explanation
  1. Line 3Capitalise the first letter of "ada" by uppercasing its first character and adding the rest.
  2. Line 6count includes the space.
  3. Line 8contains is case-sensitive, so "love" doesn't match "Love".
Example 2

Characters and substrings

Swift
let code = "SW-2024-UK"
print(code.first!, code.last!)
print(code.prefix(2), code.suffix(2))
print(code.count)

var vowels = 0
for ch in "Programming" where "aeiou".contains(ch) {
    vowels += 1
}
print("Vowels: \(vowels)")
print(String("stressed".reversed()))
Output
S K
SW UK
10
Vowels: 3
desserts
Line-by-line explanation
  1. Line 2first and last are optionals; ! unwraps them, which is safe here because the string isn't empty.
  2. Line 3prefix and suffix return Substrings, which print like strings.
  3. Line 7Loop over each character and count the vowels: o, a and i.
  4. Line 11reversed() gives the characters backwards; String() turns them back into a String.
Example 3

Splitting, joining and multi-line text

Swift
import Foundation

let input = "swift, ios,  xcode"
let tags = input.split(separator: ",").map { $0.trimmingCharacters(in: .whitespaces) }
print(tags)
print(tags.joined(separator: " | "))

let user = "Sam"
let message = """
    Hi \(user),
    You have \(tags.count) tags.
    """
print(message)
Output
["swift", "ios", "xcode"]
swift | ios | xcode
Hi Sam,
You have 3 tags.
Line-by-line explanation
  1. Line 1Foundation provides trimmingCharacters.
  2. Line 4split makes pieces; map trims each one ($0 is the current item, as the closures lesson explains).
  3. Line 5Arrays of strings print with quotes around each item.
  4. Lines 9 to 12A multi-line string; the indentation before the closing quotes is removed.

Common Swift Strings Mistakes

Using an integer index

Don't
let word = "Swift"
print(word[0])                 // error: 'subscript(_:)' is unavailable
Do
print(word.first!)             // S
print(word.prefix(1))          // S

Expecting methods to change the string

Don't
var city = "london"
city.uppercased()
print(city)                    // london
Do
var city = "london"
city = city.uppercased()
print(city)                    // LONDON

Storing a Substring where a String is expected

Don't
let firstWord: String = "Hello world".split(separator: " ")[0]   // error: Substring is not String
Do
let firstWord = String("Hello world".split(separator: " ")[0])

Swift Strings in Real Projects

Strings in apps

Apps build labels and messages with interpolation, validate input with contains and hasSuffix, and tidy what users type with trimming. Because Swift counts real characters, a username limit of 20 characters works correctly whether someone types English, Japanese or emoji. For user-facing text, apps use String(localized:) so every message can be translated.

Swift Strings FAQ

How do I get a character at a specific position in a Swift string?

Create an index from startIndex and use it as a subscript: text[text.index(text.startIndex, offsetBy: 2)]. For the first or last character, text.first and text.last are simpler and return optionals. For a single lookup with an integer you can also use Array(text)[2], but check the position is in range first.

What is the difference between String and Substring in Swift?

A Substring is a view into part of an existing string, returned by prefix, suffix, split and range subscripts. It shares the original's memory, so creating one is cheap. Convert it with String(sub) before storing it long-term, so the original large string can be freed.

How do I check if a Swift string contains another string?

Use text.contains("word"), which is case-sensitive. For a case-insensitive check, lowercase both sides: text.lowercased().contains(search.lowercased()). hasPrefix and hasSuffix check only the start or end.

Why does count give a different number from utf8.count?

count counts Characters as a reader sees them, while utf8.count counts the bytes used to store them. Letters outside basic English, accented letters and emoji take more than one byte, so "café".utf8.count is 5 while count is 4.

How do I convert a String to an Int in Swift?

Use Int(text), which returns an optional because the text might not be a valid number: Int("42") is 42 and Int("abc") is nil. Unwrap it with if let or give a default with ??. Remove spaces first, since Int(" 42") also returns nil.

Swift Strings Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the interpolation so it prints "Hello, Ada".

let name = "Ada"
print("Hello, ")
Predict the outputeasy

What does print("Swift".count) show?

Predict the outputmedium

What does this print?

print("banana".prefix(3), "banana".suffix(2))
Multiple choicemedium

Why can't you write text[2] to read a character in Swift?

Predict the outputhard

What does this print?

let words = "a b c".split(separator: " ")
print(words.joined(separator: ""))

Swift Strings Quiz

5 questions to check what you learned.

  1. How do you insert a variable's value into a string?

    • "${name}"
    • "{name}"
    • "#name"
    • "\(name)"
  2. What does "abc".uppercased() do to the original string?

    • Changes it to ABC
    • Nothing; it returns a new string
    • Deletes it
    • Throws an error
  3. What type does "hello".prefix(2) return?

    • String
    • Character
    • [Character]
    • Substring
  4. How do you write a string that spans several lines?

    • Start and end it with three double quotes
    • Use \n only
    • Use backticks
    • Use single quotes
  5. Is "Swift" == "swift" true?

    • Yes
    • Only with Foundation
    • No, comparison is case-sensitive
    • It's an error