如何在Swift 2中将十六进制字符串解析为ascii等效项

时间:2015-08-04 18:01:51

标签: regex xcode string swift swift2

在swift 2中,将十六进制字符串转换为ascii等价物的最佳方法是什么。

鉴于

let str1 = "0x4d 0x4c 0x4e 0x63"
let str2 = "4d 4c 4e 63"
let str3 = "4d4c4e63"
let str4 = "4d4d 4e63"
let str5 = "4d,4c,4e,63"

我们希望运行一个吐出的函数(或字符串扩展名):'MLNc',它是十六进制字符串的ascii等价物

伪代码:

  • 删除所有“垃圾”,逗号空格等
  • 获取“2个字符块”,然后将这些字符转换为与strtoul
  • 等效的int
  • 构建一个字符数组并将它们合并为一个字符串

部分实施

func hexStringtoAscii(hexString : String) -> String {

    let hexArray = split(hexString.characters) { $0 == " "}.map(String.init)
    let numArray = hexArray.map{  strtoul($0, nil, 16)  }.map{Character(UnicodeScalar(UInt32($0)))}
    return String(numArray)
}

这部分实现是否在正确的路径上?如果是这样,处理分块的最佳方法是怎样的

1 个答案:

答案 0 :(得分:8)

使用正则表达式匹配是一种可能的方法来提取 字符串中的“十六进制数字”。 您正在寻找的是一个可选的“0x”,紧接着是 2位十六进制数字相应的正则表达式模式为"(0x)?([0-9a-f]{2})"

然后你可以将每个匹配转换为Character并最终连接 字符为String,与您的“部分实现”非常相似。而不是strtoul(),您可以使用UInt32 初始化

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

这是Swift 2中的新功能。

该模式有两个“捕获组”(括在括号中), 第一个匹配可选的“0x”,第二个匹配 两个十六进制数字,可以检索相应的范围 rangeAtIndex(2)

这导致以下实现可以处理所有 您的示例字符串:

func hexStringtoAscii(hexString : String) -> String {

    let pattern = "(0x)?([0-9a-f]{2})"
    let regex = try! NSRegularExpression(pattern: pattern, options: .CaseInsensitive)
    let nsString = hexString as NSString
    let matches = regex.matchesInString(hexString, options: [], range: NSMakeRange(0, nsString.length))
    let characters = matches.map {
        Character(UnicodeScalar(UInt32(nsString.substringWithRange($0.rangeAtIndex(2)), radix: 16)!))
    }
    return String(characters)
}

(有关转换为NSString的说明,请参阅Swift extract regex matches。)

请注意,此功能非常宽松,只需搜索 2位十六进制字符串并忽略所有其他字符,所以这个 也会被接受:

let str6 = "4d+-4c*/4e0x63"

Swift 3的更新:

func hexStringtoAscii(_ hexString : String) -> String {

    let pattern = "(0x)?([0-9a-f]{2})"
    let regex = try! NSRegularExpression(pattern: pattern, options: .caseInsensitive)
    let nsString = hexString as NSString
    let matches = regex.matches(in: hexString, options: [], range: NSMakeRange(0, nsString.length))
    let characters = matches.map {
        Character(UnicodeScalar(UInt32(nsString.substring(with: $0.rangeAt(2)), radix: 16)!)!)
    }
    return String(characters)
}