Back to blog

# Play With Code: Palindromes In Swift

By Aasif Khan | Last Updated on May 22nd, 2023 3:51 pm | 4-min read

The date 02-02-2020 is a palindrome. Palindromes are words that read the same forward as backward. And they’re great fun to play with in Swift! In this app development tutorial, we’ll discuss and code 3 approaches to check if a string is a palindrome in Swift.

## What’s A Palindrome?

Firs things first: What’s a palindrome?

A palindrome is a word, number, phrase or other sequence that reads the same forward as it reads backward. A few examples:

• A man, a plan, a canal – Panama
• Doc, note: I dissent. A fast never prevents a fatness. I diet on cod.
• Step on no pets

(Source: Palindrome)

A palindrome is a nerdy word joke!

If you look closely, you’ll see that you can essentially “flip” or rotate a palindrome around its middle. What’s on the left of the middle, is also on the right. It doesn’t matter if the number of characters is even or odd. And as we can see in the examples above, palindromes can also include punctuation.

You can get pretty crazy with palindromes. For example, a Lychrel number is an integer number that cannot form a palindrome after repeated reversal and addition of its digits. Take 56, which becomes palindromic after one iteration: 56 + 65 = 121.

And as you’ve guessed, palindromes are a prime subject for playing around with strings in Swift!

## Palindrome 1: Comparing String Characters

We’re going to figure out if a given string is a palindrome, by using Swift programming. Before we write some code, we’ll have to agree on a strategy or algorithm.

Here’s one such algorithm:

1. Take the first and last character of the string
2. Compare them against each other:
• If they’re the same, continue with step 3
• If they’re not the same, stop, the string is not a palindrome
3. Look at the next character, so the second one from the start, and the before last character at the end, then go to step 2

With this algorithm, we’re essentially “walking” the characters from both the start and the end of the string. You compare them against each other, and when every character pair is equal, the string is a palindrome.

Let’s code that in Swift. We’ll start by defining the function isPalindrome(_:). Like this:

func isPalindrome(_ value: String) -> Bool
{

}

In the above code, we’ve defined a function named isPalindrome(_:). It has one unnamed parameter value of type String. The function returns a Bool value, either true or false. We’re going to check if value is a palindrome, and return true if it is, and false if it’s not.

Next up, we’re adding the following code to the function:

let len = value.count / 2

for i in 0..

• We’re first dividing the length of the input string value by 2. We’ll only need to iterate half of the string, because we’re starting at both ends. The length of half the string is assigned to len.
• The for loop will iterate from 0 to len (exclusive). So, when the input string has 7 characters, we’ll loop from 0 to 3: 0, 1, 2, 3. We can use these integer values as the constant i within the loop.
• The above code also uses a trick. What happens when the length of the string is an odd number, like 7? In that case, len will be 3. The code value.count / 2 is essentially 7 / 2, which is 3.5, but since both 7 and 3 are integers, the resulting type of len is an integer too. You can’t assign a decimal value, like 3.5, to an integer. As a result, the fraction of the decimal value is “chopped off”, and we end up with 3.

OK, next up. We’ll need to get the characters at the start and end of the input string. Add the following code inside the loop:

let start = value.index(value.startIndex, offsetBy: i)
let end = value.index(value.endIndex, offsetBy: (i * -1) – 1)

What’s going on here?

• The first line, with value.index(…), will create an index that starts at the beginning of the string plus i. So, when i is 0, we’ll get the first character of the string. When i = 1, we’ll get the second, and so on.
• The second line does the same thing, except it starts at the end of the string and goes backwards. We start at the end of the string, then subtract i from the index number, and subtract 1 to get the one before that.

In Swift, string indices are complicated. First, we’ll need to work with an index to get a character from a string. Integers as indices won’t work. For now, let’s assume that start and end correspond to the first and last positions in the string.

Then, add the following code in the for loop:

if value[start] != value[end] {
return false
}

The above code will compare the character for the start index with the character for the end index, by using subscript syntax. If they’re not the same, the function returns false, because this string is not a palindrome!

Finally, at the end of the function, outside the for loop, add this code:

return true

Why do we need that? When the for loop has walked all the characters in the string, we’ve proved that they are all equal (not not equal), so the string is a palindrome! We return true.

Here’s the entire function:

func isPalindrome(_ value: String) -> Bool
{
let len = value.count / 2

for i in 0.. Bool
{
let len = value.count / 2

for i in 0..

## Palindrome 2: Solving It Recursively

Let’s continue with another approach. Instead of using a for loop, we’ll recursively iterate the string. We’ll take smaller and smaller pieces of the string, continually checking if the first and last characters are the same.

Here, check this out:

func isPalindrome( _ value: String) -> Bool
{
guard value.count >= 2 else {
return true
}

let end = value.index(value.endIndex, offsetBy: -1)

if value[value.startIndex] == value[end] {
let start = value.index(value.startIndex, offsetBy: 1)
return isPalindrome(String(value[start..

• hannah → h == h → anna
• anna → a == a → nn
• nn → n == n → DONE!
• The next time isPalindrome(_:) runs, the string has become shorter. We check the first and last characters again, and call the function again, and again, and again, until…

Until when? That’s where this block of code comes in:

guard value.count >= 2 else {
return true
}

The guard statement will check if value.count is bigger than or equal to 2, and if it isn’t, the function will return true. Differently said, when the length of value is 1 or 2, the function returns true.

Here’s why:

• When the input string is empty, it’s length is 0, and given that we’ve come so far, the entire input string must be a palindrome. If it weren’t, we would have called return false sooner.
• When the input string’s length is 1, we assume the entire string is a palindrome, because we’ve come so far without returning false. Also, a string of one character is by definition a palindrome.
• When the input string’s length is 2 or more, the else block is not invoked and the function executes normally. Differently said, an input string xx will continue, and call isPalindrome(_:) once more, with an empty string as input.

Awesome!

Why are let end … and let start … so oddly placed? That’s because of value[start..

## Palindrome 3: This One Trick…

So far we’ve gone through a lot of trouble to naively check every character of the input string against the other one. We’ve walked from one end of the string to the middle, and from the other end to the middle, checking every character against the other.

Based on this, we can assert that a string is a palindrome if both halves of the string are equal to each other, in reverse. Like this:

• hannah → han + nah → han + han → han == han
• rotor → ro + or → ro + ro → ro == ro (ignoring middle t)

Provided that both string halves can be mirrored, we might as well reverse the entire string if both halves are the same anyway. Said differently, would you notice if I spelled hannah in reverse? (No.) Conversely, would you notice that I spelled doghouse in reverse? (Yes.)

And that, dear coder, is why the simplest algorithm to check if a given string is a palindrome is…

func isPalindrome(_ value: String) -> Bool
{
return value == String(value.reversed())
}

A string is a palindrome if it’s equal to the same string in reverse. Awesome!

By the way, while we’re at it, you may have noticed that many palindromes are sentences, riddles, etc. Since string equality in Swift is strict, i.e. it includes punctuation too, we’ll need something to sanitize one such riddle if we want to run it through our isPalindrome(_:) function.

Here’s how you do that:

func sanitize(_ value: String) -> String
{
return value.lowercased().replacingOccurrences(of: “[^a-z]+”, with: “”, options: .regularExpression)
}

The sanitize(_:) function will take a value string as input, and returns the same string as lowercase, with any character but lowercase A to Z removed. It uses regular expressions to replace characters in the string.

• Step on no pets becomes steponnopets, for which isPalindrome(_:) returns true
• A man, a plan, a canal – Panama becomes amanaplanacanalpanama, which is a palindrome

And there you have it: palindromes. We’ve discussed 3 approaches to check if a given string is a palindrome, and we’ve touched on many Swift syntaxes and topics in between.

The big question of course, is when the next 02-02-2020 palindromic date occurs…

var value = “10” // Anything but a palindrome
var day = 1 // Increase by one day
var date = Date() // Now

let formatter = DateFormatter()
formatter.dateFormat = “ddMMyyyy”

// Keep checking `value` for palindrome until one is found
while isPalindrome(value) == false
{
// Add 1 day to `date`, assign ddMMyyyy format to `value`
let component = DateComponents(day: day)
date = Calendar.current.date(byAdding: component, to: date)!
value = formatter.string(from: date)
}

print(value)

Aasif Khan

Head of SEO at Appy Pie