According to Swift - Converting String to Int, there's a String
method toInt()
.
But, there's no toUInt()
method. So, how to convert a String
to a Uint
?
Update for Swift 2/Xcode 7:
As of Swift 2, all integer types have a (failable) constructor
init?(_ text: String, radix: Int = default)
which replaces the toInt()
method of String
, so no custom
code is needed anymore for this task:
print(UInt("1234")) // Optional(1234)
// This is UInt.max on a 64-bit platform:
print(UInt("18446744073709551615")) // Optional(18446744073709551615)
print(UInt("18446744073709551616")) // nil (overflow)
print(UInt("1234x")) // nil (invalid character)
print(UInt("-12")) // nil (invalid character)
Old answer for Swift 1.x:
This looks a bit complicated, but should work for all numbers in the
full range of UInt
, and detect all possible errors correctly
(such as overflow or trailing invalid characters):
extension String {
func toUInt() -> UInt? {
if contains(self, "-") {
return nil
}
return self.withCString { cptr -> UInt? in
var endPtr : UnsafeMutablePointer<Int8> = nil
errno = 0
let result = strtoul(cptr, &endPtr, 10)
if errno != 0 || endPtr.memory != 0 {
return nil
} else {
return result
}
}
}
}
Remarks:
The BSD library function strtoul
is used for the conversion.
The endPtr
is set to first "invalid character" in the input string,
therefore endPtr.memory == 0
must be hold if all characters
could be converted.
In the case of a conversion error, the global errno
variable is set
to a non-zero value (e.g. ERANGE
for an overflow).
The test for a minus sign is necessary because strtoul()
accepts
negative numbers (which are converted to the unsigned number with the
same bit pattern).
A Swift string is converted to a C string "behind the scenes" when
passed to a function taking a char *
parameter, so one could be
tempted to call strtoul(self, &endPtr, 0)
(which is what I did in
the first version of this answer). The problem is that the automatically
created C string is only temporary and can already be invalid when
strtoul()
returns, so that endPtr
does not point to a
character in the input string anymore. This happened when I tested the code in the Playground. With self.withCString { ... }
, this problem does not occur because the C string is valid throughout the execution
of the closure.
Some tests:
println("1234".toUInt()) // Optional(1234)
// This is UInt.max on a 64-bit platform:
println("18446744073709551615".toUInt()) // Optional(18446744073709551615)
println("18446744073709551616".toUInt()) // nil (overflow)
println("1234x".toUInt()) // nil (invalid character)
println("-12".toUInt()) // nil (invalid character)