NEW: Master Swift design patterns with my latest book! >>

How to calculate the ROT13 of a string

Written by Paul Hudson    @twostraws

ROT13 is a simple algorithm that shifts letters in a string forward 13 places. It’s obviously not suitable for any serious encryption, but it’s very useful for hiding text so its meaning is not obvious – posting spoilers on a forum, for example, is best done using ROT13 to avoid someone getting annoyed.

It’s not hard to write a rot13() function, but it is a little harder to wrap it up neatly so you avoid global variables while still making it easy to use. Because you can’t add stored variables to an extension on String, the cleanest thing to do is create a new ROT13 type that can store the transformation from regular letters to ROT13, then run the calculation.

In code, it looks like this:

struct ROT13 {
    // create a dictionary that will store our character mapping
    private static var key = [Character: Character]()

    // create arrays of all uppercase and lowercase letters
    private static let uppercase = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
    private static let lowercase = Array("abcdefghijklmnopqrstuvwxyz")

    static func string(_ string: String) -> String {
        // if this is the first time the method is being called, calculate the ROT13 key dictionary
        if ROT13.key.count == 0 {
            for i in 0 ..< 26 {
                ROT13.key[ROT13.uppercase[i]] = ROT13.uppercase[(i + 13) % 26]
                ROT13.key[ROT13.lowercase[i]] = ROT13.lowercase[(i + 13) % 26]
            }
        }

        // now return the transformed string
        let transformed = string.map { ROT13.key[$0] ?? $0 }
        return String(transformed)
    }
}

I’ve used private properties there because there’s no reason these implementation details should leak out, and it’s all static because there’s no need to create new ROT13 instances every time we need to run the conversion.

With that in place we can write an extension on String to calculate the ROT13 using our struct:

extension String {
    func rot13() -> String {
        return ROT13.string(self)
    }
}

That extension can now be called on a regular string, so users don’t need to care about how we implemented ROT13:

print("Hello, world!".rot13())

Available from iOS

Did this solution work for you? Please pass it on!

Other people are reading…

About the Swift Knowledge Base

This is part of the Swift Knowledge Base, a free, searchable collection of solutions for common iOS questions.

Get my latest video for free

Learn about value types, functional programming, and protocol-oriented programming in this new video – it's free!

Click here to visit the Hacking with Swift store >>