Last active
August 10, 2022 12:30
-
-
Save insidegui/6a46659bbd15a516c8462d3f4cb2c036 to your computer and use it in GitHub Desktop.
Implementation of the "atoi" function in Swift (just an exercise, not for use in production)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Implementation of the "atoi" function in Swift. | |
This implementation is an exercise and should not be used in production, | |
Swift has built-in types and functions that can do this sort of conversion. | |
*/ | |
/// Parses the input string as a 32-bit integer. | |
/// Returns `nil` if the input contains non-ASCII characters, or is not a valid number. | |
func myAtoi(_ input: String) -> Int32? { | |
/// The base ASCII code, where the numbers begin. | |
let base = UInt8(48) | |
/// This function will be applied to the number before the function returns. | |
/// It's used to change the sign according to the input. | |
var signfn: ((Int32) -> Int32) = { $0 } | |
/// This will be updated as the input is parsed and returned from the function. | |
/// It is an `Int` instead of an `Int32` because the value can extrapolate the maximum value | |
/// that `Int32` can hold depending upon the input. | |
/// We'll clamp this value before returning it as an `Int32`. | |
var output: Int = 0 | |
for (index, char) in input.enumerated() { | |
/// We only work with ASCII characters, an input | |
/// that contains non-ASCII characters is invalid. | |
guard let ascii = char.asciiValue else { return nil } | |
/// If the character is not a number. | |
guard ascii >= base else { | |
/// The only position where a non-number character | |
/// is acceptable is in the first position (for the sign). | |
guard index == 0 else { return nil } | |
/// The only acceptable non-number character in the first | |
/// position is ASCII code 45 (the minus sign). | |
guard ascii == 45 else { return nil } | |
/// Found the minus sign in front of the number string, | |
/// set the sign function to multiply the number by -1. | |
signfn = { $0 * -1 } | |
continue | |
} | |
/// Compute the current digit by subtracting the base | |
/// ASCII code from the current digit's ASCII code. | |
let digit = Int(ascii - base) | |
/// Since we're working with the decimal system, each time | |
/// we find a new digit to the right, we multiply the | |
/// current number by 10, then add the new digit to the result. | |
output = (output * 10) + digit | |
} | |
/// The nested max/min ensures the final value | |
/// lies between Int32.min and Int32.max. | |
let clamped = Int32(max(min(output, Int(Int32.max)), Int(Int32.min))) | |
/// Run signfn, which will multiply the number by -1 | |
/// if a minus sign was found in the first position. | |
return signfn(clamped) | |
} | |
myAtoi("0") == 0 | |
myAtoi("123") == 123 | |
myAtoi("2048") == 2048 | |
myAtoi("-999") == -999 | |
myAtoi("99999999999999") == Int32.max | |
myAtoi("-🤡123") == nil |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment