More fun with Swift 5 String Interpolation: Radix formatting

I’m still kicking the tires and enjoying the new string interpolation features in Swift 5. Today’s extension enables (optionally padded) radix-based interpolation. You interpolate a number and specify a radix, the numerical base used to present it.

For example:

"\(42, radix: .hex)" // 2a
"\(42, radix: .binary)" // 101010
"\(42, radix: .octal)" // 52
"\(0x2a, radix: .decimal)" // 42
"\(15, radix: .hex, prefix: true, toWidth: 2)" // 0x0F

With padding you can ensure, for example, that a non-wide color is presented using two digits per color, with or without a prefix. Start with 15 and end up with F, 0F, or 0x0F , as desired.

It’s a simple extension for a task I use pretty regularly. I decided to use lowercase prefixes (0x and 0b) and uppercase hex (7F vs 7f). If you’d rather swap that out, change the prefix property and/or the first line in the interpolation:

public extension String.StringInterpolation {
    /// Represents a single numeric radix
    enum Radix: Int {
        case binary = 2, octal = 8, decimal = 10, hex = 16
        
        /// Returns a radix's optional prefix
        var prefix: String {
             return [.binary: "0b", .octal: "0o", .hex: "0x"][self, default: ""]
        }
    }
    
    /// Return padded version of the value using a specified radix
    mutating func appendInterpolation<I: Binary Integer>(_ value: I, radix: Radix, prefix: Bool = false, toWidth width: Int = 0) {
        
        // Values are uppercased, producing `FF` instead of `ff`
        var string = String(value, radix: radix.rawValue).uppercased()
        
        // Strings are pre-padded with 0 to match target widths
        if string.count < width {
            string = String(repeating: "0", count: max(0, width - string.count)) + string
        }
        
        // Prefixes use lower case, sourced from `String.StringInterpolation.Radix`
        if prefix {
            string = radix.prefix + string
        }
        
        appendInterpolation(string)
    }
}

I haven’t had a chance to test this much so if you see any issues, please let me know.

I have more to follow with more general NumberFormatter approaches that extend the interpolator (thanks, Dave DeLong!) and some fun suggestions and examples that will cover the new custom string delimiters.

Update James Dempsey writes:

In your post “More fun with Swift 5 String Interpolation: Radix formatting”, I noticed one very minor thing. The String initializer that takes a value and a radix also has an uppercase parameter. So the code
var string = String(value, radix: radix.rawValue).uppercased()
could be
var string = String(value, radix: radix.rawValue, uppercase: true)
I’m guessing that saves the tiny bit of work of creating a new string and transforming the old string. Definitely a minor point, but I always enjoy and find useful the precision of your explanations, so I thought you’d be interested.
Thank you, James!

Comments are closed.