Swift - 将具有长度的UnsafePointer<UInt8>转换为字符串

10

我考虑了很多类似的问题,但是编译器仍然无法接受这个。

Socket Mobile API(使用Objective-C编写)将ISktScanDecodedData传递到Swift中的委托方法中(数据可能是二进制的,这也许是为什么它不作为字符串提供的原因):

func onDecodedData(device: DeviceInfo?, DecodedData d: ISktScanDecodedData?) {
  let symbology: String = d!.Name()
  let rawData: UnsafePointer<UInt8> = d!.getData()
  let rawDataSize: UInt32 = decoded!.getDataSize()
  // want a String (UTF8 is OK) or Swifty byte array...
}

在C#中,这段代码将原始数据转换为字符串:

string s = Marshal.PtrToStringAuto(d.GetData(), d.GetDataSize());

在Swift中,我可以使用UnsafeArray,但之后就卡住了:

let rawArray = UnsafeArray<UInt8>(start: rawData, length: Int(rawDataSize))

另外我看到了String.fromCStringNSString.stringWithCharacters,但是这两者都无法接受手头的参数类型。例如,如果我可以将UnsafePointer<UInt8>转换为UnsafePointer<()>,那么这个函数就可以使用了(尽管我不确定它是否安全)。

NSData(bytesNoCopy: UnsafePointer<()>, length: Int, freeWhenDone: Bool)

有没有明显的方法从所有这些中获取一个字符串?


能告诉我们 Marshal 是做什么的吗?如果有一个 ds 的十六进制转储示例就更好了。 - zaph
1
@Zaph Marshal 是一个 C# 类,具有用于在各种类型之间进行转换的实用方法,包括从具有数据块指针到实际字符串的好方法。 - Billy Mailman
2个回答

15

这应该可以正常工作:

let data = NSData(bytes: rawData, length: Int(rawDataSize))
let str = String(data: data, encoding: NSUTF8StringEncoding)

Swift 3 更新:

let data = Data(bytes: rawData, count: Int(rawDataSize))
let str = String(data: data, encoding: String.Encoding.utf8)

如果数据不代表有效的UTF-8序列,则结果字符串为nil


谢谢!我看到了以下自动完成,但没想到它会起作用:NSData(bytes: ConstUnsafePointer<()>, length: Int) - macu
1
注意:并非所有数据都可以形成UTF8字符串。 - zaph
谢谢,非常有帮助。 - Saleh Enam Shohag

15

这样怎么样,使用'纯'的Swift 2.2而不是使用NSData:

public extension String {

  static func fromCString
    (cs: UnsafePointer<CChar>, length: Int!) -> String?
  {
    if length == .None { // no length given, use \0 standard variant
      return String.fromCString(cs)
    }

    let buflen = length + 1
    var buf    = UnsafeMutablePointer<CChar>.alloc(buflen)
    memcpy(buf, cs, length))
    buf[length] = 0 // zero terminate
    let s = String.fromCString(buf)
    buf.dealloc(buflen)
    return s
  }
}

及Swift 3:

public extension String {

  static func fromCString
    (cs: UnsafePointer<CChar>, length: Int!) -> String?
  {
    if length == nil { // no length given, use \0 standard variant
      return String(cString: cs)
    }

    let buflen = length + 1
    let buf    = UnsafeMutablePointer<CChar>.allocate(capacity: buflen)
    memcpy(buf, cs, length)
    buf[length] = 0 // zero terminate
    let s = String(cString: buf)
    buf.deallocate(capacity: buflen)
    return s
  }
}

承认为了添加零终止符而分配缓冲区并复制数据有点愚蠢。

显然,正如Zaph所提到的那样,您需要确保对字符串编码的假设是正确的。


ConstUnsafePointer在Swift中已不再可用。您能否更新您的帖子? - qwerty_so
现在ConstUnsafePointer已经改为UnsafePointer,而另一个是UnsafeMutablePointer。 - hnh
memcpy(buf, cs, UInt(lengh)) 应该改为 memcpy(buf, cs, Int(length)) - mkhoshpour
memcpy()的API映射在某些Swift版本中发生了变化。 - hnh

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