Part of Swift with Copilot

Swift reverse a string word by word

Sandy LaneSandy Lane

Video: Swift reverse a string word by word by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

Swift with Copilot: Reverse a String Word by Word

str.split(separator: " ").reversed().joined(separator: " "). Three ops in one line: split, reverse, rejoin. The "reverse the words, not the letters" trick.

A common interview question. Two common confusions: reversing letters (olleh) vs reversing words (world hello). This is the latter.

The Copilot prompt

// Reverse a sentence word by word: "hello world" -> "world hello"
let sentence = "the quick brown fox"

Copilot completes:

let sentence = "the quick brown fox"
let reversed = sentence
  .split(separator: " ")
  .reversed()
  .joined(separator: " ")

print(reversed)
// "fox brown quick the"

Walkthrough

split(separator: " ")

"the quick brown fox".split(separator: " ")
// ["the", "quick", "brown", "fox"]

split returns [Substring] — substrings reference the original string's storage (no copy). For most uses, treat them like [String].

By default, consecutive separators collapse and empty pieces are dropped:

"a   b   c".split(separator: " ")
// ["a", "b", "c"] — 3 elements

"a   b   c".split(separator: " ", omittingEmptySubsequences: false)
// ["a", "", "", "b", "", "", "c"] — 7 elements

For "split on any whitespace":

"hello\tworld\nfoo".split(whereSeparator: \.isWhitespace)
// ["hello", "world", "foo"]

\.isWhitespace is a KeyPath — concise way to pass "is this character whitespace?"

reversed()

[1, 2, 3].reversed()
// ReversedCollection<[Int]>([3, 2, 1])

Returns a lazy ReversedCollection. To convert to Array, wrap with Array(...). For our pipeline, we don't need to — joined accepts any sequence.

joined(separator:)

["world", "fox", "hello"].joined(separator: " ")
// "world fox hello"

joined() (no separator) concatenates without delimiter. joined(separator: ", ") puts the separator between.

For arrays of Substring:

let parts: [Substring] = ["a", "b", "c"]
let s = parts.joined(separator: "-")
// "a-b-c"

joined returns String regardless of input element type.

A function

extension String {
  func reversedWords() -> String {
    self.split(separator: " ")
        .reversed()
        .joined(separator: " ")
  }
}

print("hello world".reversedWords())
// "world hello"

Now any String has .reversedWords(). Extensions are Swift's clean way to add behavior to existing types.

Edge cases

"".reversedWords()                  // ""
"   ".reversedWords()               // "" — whitespace dropped
"  hello   world  ".reversedWords() // "world hello" — whitespace collapsed
"single".reversedWords()             // "single"

If you need to preserve original whitespace exactly, split isn't right — use a regex.

Reverse letters (different problem)

let letters = String("hello".reversed())
// "olleh"

String.reversed() is letter reversal. String(...) materializes.

For Unicode-aware:

let s = "Hello 👋"
String(s.reversed())   // "👋 olleH" — emoji stays as one grapheme

Swift's Character is a grapheme cluster, so emoji and combining marks survive reversal correctly.

Sentence-aware (with punctuation)

"Hello, world!".split(separator: " ").reversed().joined(separator: " ")
// "world! Hello,"

Punctuation sticks to the words. For "drop punctuation":

let cleaned = "Hello, world!"
  .components(separatedBy: CharacterSet.punctuationCharacters)
  .joined()
// "Hello world"

cleaned.split(separator: " ").reversed().joined(separator: " ")
// "world Hello"

components(separatedBy:) is Foundation's older API; works the same.

Performance

split + reversed + joined is O(n) — linear in input length. For huge strings, this is fine. For loops processing millions of strings, profile first; usually no faster path exists.

Common stumbles

split returns Substring, not String. Most APIs accept Substring because it conforms to StringProtocol. If a function strictly wants String, do String(substring).

reversed() is lazy. It doesn't allocate. To materialize: Array(...). Or just chain to .joined(...) like our example.

Multiple consecutive spaces. Collapsed by default. Use omittingEmptySubsequences: false to preserve.

Reverse String directly. let r = "hi".reversed() is a ReversedCollection<String> — not a String. Wrap: String("hi".reversed()).

Reversing emoji. Works correctly because Swift treats grapheme clusters as one Character. Don't index into bytes.

What's next

Episode 8: Is 2023 a leap year? Calendar arithmetic.

Recap

split(separator: " ").reversed().joined(separator: " ") for word-reverse. split returns [Substring] (zero-copy). \.isWhitespace for any-whitespace split. String("hi".reversed()) for letter reverse — Unicode-aware. Extensions add reversedWords() to all strings. components(separatedBy:) is the Foundation alternative.

Next episode: leap years.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.