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

6
在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将这些字符转换为整数等效值。
  • 构建字符数组并将它们合并成一个字符串。
部分实现:
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)
}

这个部分的实现是正确的吗?如果是,最好处理块的方法是什么?


你需要使用正则表达式来完成这个任务。 - poosliver
第四个字符串不同 :) - Martin R
1个回答

12

使用正则表达式匹配是从字符串中提取“十六进制数”可能的方法之一。 你要找的是一个可选的“0x”,后跟恰好2个十六进制数字。对应的正则表达式模式为"(0x)?([0-9a-f]{2})"

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

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)
}

(请参见Swift提取正则表达式匹配项以了解转换为 NSString 的说明。)

请注意,此功能相当宽松,它只搜索2位十六进制字符串并忽略所有其他字符,因此也将接受此字符串:

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

Swift 5.1更新:

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.range(at: 2)), radix: 16)!)!)
    }
    return String(characters)
}

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