Swift: How to convert String to UInt?

后端 未结 5 1010
太阳男子
太阳男子 2021-02-15 00:42

According to Swift - Converting String to Int, there\'s a String method toInt().

But, there\'s no toUInt() method. So, how to conv

相关标签:
5条回答
  • 2021-02-15 01:22

    Use Forced Unwrapping or Optional Binding to make sure the string can be converted to UInt. eg:

    let string = "123"
    let number = UInt(string) //here number is of type *optional UInt*
    
    //Forced Unwrapping
    
    if number != nil {
      //converted to type UInt
    }
    
    0 讨论(0)
  • 2021-02-15 01:24

    Please, for the love of not crashing, don’t use ! to do this.

    It’s easy to tack a map on the end of toInt to convert it to an optional UInt:

    let str = "4"
    let myUInt = str.toInt().flatMap { $0 < 0 ? nil : UInt($0) }
    

    then use the usual unwrapping techniques on myUInt.

    And if you find yourself doing this a lot:

    extension String {
        func toUInt() -> UInt? {
            return self.toInt().flatMap { $0 < 0 ? nil : UInt($0) }
        }
    }
    
    let str = "-4"
    if let myUInt = str.toUInt() {
        println("yay, \(myUInt)")
    }
    else {
        println("nuh-uh")
    }
    

    edit: as @MartinR points out, while safe, this doesn’t extract the full range of possible values for a UInt that Int doesn’t cover, see the other two answers.

    0 讨论(0)
  • 2021-02-15 01:25

    just use UInt's init:

    let someString = "4"
    
    UInt(someString.toInt()!) // 4
    
    0 讨论(0)
  • 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)
    
    0 讨论(0)
  • 2021-02-15 01:35

    You might be interested in a safer solution similar to:

    let uIntString = "4"
    let nonUIntString = "foo"
    
    extension String {
        func toUInt() -> UInt? {
            let scanner = NSScanner(string: self)
            var u: UInt64 = 0
            if scanner.scanUnsignedLongLong(&u)  && scanner.atEnd {
                return UInt(u)
            }
            return nil
        }
    }
    
    uIntString.toUInt()     // Optional(4)
    nonUIntString.toUInt()  // nil
    

    Hope this helps

    // Edited following @Martin R. suggestion

    0 讨论(0)
提交回复
热议问题