有没有一个 Swift 的本地函数可以将一个数字转换成十六进制字符串?

56

有没有一种原生的Swift方法可以将任何(至少是整数)数字以字符串形式表示为十六进制?反之亦然。它不能使用Foundation框架。例如,String类具有一个函数

func toInt() -> Int?

将表示整数的字符串转换为其Int值。我正在寻找类似的东西,使用十六进制字符串。我知道这很容易实现,但如果Swift已经有了它,那就更好了。否则,如果您已经创建了String和Int的扩展来实现以下内容:

let anHex = "0xA0"
if let anInt = anHex.toInt() {
   println(anInt)               // prints 128
   println(anInt.toHexString()) // prints "0xA0"
}

我知道这不是什么复杂的技术问题,但如果可以请分享一下。

附言:这与this question类似,不同之处在于那个问题与Foundation框架非常相关,而我在我的代码中没有使用它(也没有导入任何其他内容),并且现在我想以此为基础进行学习。


2
请查看 https://dev59.com/uV8d5IYBdhLWcg3weiB- 获取一个方向的信息,然后查看https://dev59.com/G18e5IYBdhLWcg3wAWrs 获取另一个方向的信息(仅将基数2替换为基数16)。前者需要import Darwin,而后者是“仅限Swift”。 - Martin R
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Hot Licks
1
我现在明白了。所以 "String(num,radix:base)" 是我正在寻找的内容,因为我现在不需要导入任何东西。好的,谢谢。我必须强迫自己在查看源代码时查看初始化器。这是我忽略的第二个。 - Michele Dall'Agata
4个回答

105

Swift 2开始,所有整数类型都有一个构造器。

init?(_ text: String, radix: Int = default)

这样就可以使用内置方法完成整数到十六进制字符串和十六进制字符串到整数之间的转换。例如:

let num = 1000
let str = String(num, radix: 16)
print(str) // "3e8"

if let num2 = Int(str, radix: 16) {
    print(num2) // 1000
}

将整数转换为十六进制字符串可以使用以下方法:

(Swift 1 的旧回答:)

let hex = String(num, radix: 16)

(例如,请参阅如何在Swift中将十进制数转换为二进制?)。 这不需要导入任何框架,且适用于2到36之间的任何进位数。
使用BSD库函数strtoul()(请参阅如何在Swift中将二进制数转换为十进制?)可以将十六进制字符串转换为整数,但需要import Darwin
否则,据我所知,没有内置的Swift方法。 下面是一个扩展,它按照给定的基数将字符串转换为数字:
extension UInt {
    init?(_ string: String, radix: UInt) {
        let digits = "0123456789abcdefghijklmnopqrstuvwxyz"
        var result = UInt(0)
        for digit in string.lowercaseString {
            if let range = digits.rangeOfString(String(digit)) {
                let val = UInt(distance(digits.startIndex, range.startIndex))
                if val >= radix {
                    return nil
                }
                result = result * radix + val
            } else {
                return nil
            }
        }
        self = result
    }
}

示例:

let hexString = "A0"
if let num = UInt(hexString, radix: 16) {
    println(num)
} else {
    println("invalid input")
}

2
小修正:String(num, radix: 16) 可以用于2到36进制。 - vacawama
2
@vacawama:谢谢,已更正。对于strtoul()和上述扩展方法也是如此。 - Martin R
2
有没有办法避免去除任何前导的 0 字符?例如,使用基数 16,我想要 "0F",而不是得到 "F" - user4691305
4
@Oscar:为什么这么复杂?在Swift 3中,“builtin”构造函数UInt(“DEADBEAF”,radix:16)也可以使用。 - Martin R
啊,这确实让事情变得更容易了 :) 谢谢! - Oscar
显示剩余3条评论

28

更新: Xcode 12.5 • Swift 5.4

extension StringProtocol {
    func dropping<S: StringProtocol>(prefix: S) -> SubSequence { hasPrefix(prefix) ? dropFirst(prefix.count) : self[...] }
    var hexaToDecimal: Int { Int(dropping(prefix: "0x"), radix: 16) ?? 0 }
    var hexaToBinary: String { .init(hexaToDecimal, radix: 2) }
    var decimalToHexa: String { .init(Int(self) ?? 0, radix: 16) }
    var decimalToBinary: String { .init(Int(self) ?? 0, radix: 2) }
    var binaryToDecimal: Int { Int(dropping(prefix: "0b"), radix: 2) ?? 0 }
    var binaryToHexa: String { .init(binaryToDecimal, radix: 16) }
}

extension BinaryInteger {
    var binary: String { .init(self, radix: 2) }
    var hexa: String { .init(self, radix: 16) }
}

测试:

print("7fffffffffffffff".hexaToDecimal)      // "9223372036854775807" decimal integer
print("0x7fffffffffffffff".hexaToDecimal)    // "9223372036854775807" decimal integer
print("7fffffffffffffff".hexaToBinary) // "111111111111111111111111111111111111111111111111111111111111111" binary (String)
print("0x7fffffffffffffff".hexaToBinary) // "111111111111111111111111111111111111111111111111111111111111111"

print("255".decimalToHexa)   // "ff"       hexa (String)
print("255".decimalToBinary) // "11111111" binary (String)
0b11111111

print("11111111".binaryToHexa)      // "ff"  hexa (String)
print("0b11111111".binaryToHexa)    // "ff"  hexa (String)
print("11111111".binaryToDecimal)   // 255 decimal (Int)
print("0b11111111".binaryToDecimal) // 255 decimal (Int)

print(255.binary) // "11111111" binary (String)
print(255.hexa)   // "ff"       hexa (String)

2
非常详尽和有帮助的回答!顺便提一下,当从十六进制转换为十进制字符串时,这段代码不会在左侧填充0以形成一个完整的字节。这可能对任何人都不是问题,但还是值得指出的。再次感谢! - kbpontius
1
https://dev59.com/dlwX5IYBdhLWcg3wpw5h#33548238 - Leo Dabus

19

Swift 3

String 转换为 UInt

let str = "fcd7d7"
let number = UInt(str, radix: 16)!
print(number)

结果:16570327

UInt转换为十六进制String

let number = UInt(exactly: 16570327)!
let str = String(number, radix: 16, uppercase: false)
print(str)

结果:fcd7d7


3

对于浮点数,如果你想要将IEEE754浮点数转换为十六进制

extension Float {
 func floatToHex()->String {
    return String(self.bitPattern, radix: 16, uppercase: true)
 }
}
let f:Float = 3.685746e+19
let hex = f.floatToHex()

print("\(hex)")//5FFFC000

或者反过来。
extension String {

 func hexToFloat() -> Float {
    var toInt = Int32(truncatingBitPattern: strtol(self, nil, 16))
    var toInt = Int32(_truncatingBits: strtoul(self, nil, 16)) //For Swift 5
    var float:Float32!
    memcpy(&float, &toInt, MemoryLayout.size(ofValue: float))
    return float
 }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接