How to convert UInt8 byte array to string in Swift
ArraysSwiftArrays Problem Overview
I am facing problems while converting UInt8
Byte array to string in swift. I have searched and find a simple solution
String.stringWithBytes(buff, encoding: NSUTF8StringEncoding)
but it is showing error String.type
does not have a member stringWithBytes
. Can anyone suggest me a solution ?
this is my code where i am getting an NSData
and converted into bytes array and then i have to convert that byte array into string.
let count = data.length / sizeof(UInt8)
var array = [UInt8](count: count, repeatedValue: 0)
data.getBytes(&array, length:count * sizeof(UInt8))
String.stringWithBytes(buff, encoding: NSUTF8StringEncoding)
Arrays Solutions
Solution 1 - Arrays
Update for Swift 3/Xcode 8:
String from bytes: [UInt8]
:
if let string = String(bytes: bytes, encoding: .utf8) {
print(string)
} else {
print("not a valid UTF-8 sequence")
}
String from data: Data
:
let data: Data = ...
if let string = String(data: data, encoding: .utf8) {
print(string)
} else {
print("not a valid UTF-8 sequence")
}
Update for Swift 2/Xcode 7:
String from bytes: [UInt8]
:
if let string = String(bytes: bytes, encoding: NSUTF8StringEncoding) {
print(string)
} else {
print("not a valid UTF-8 sequence")
}
String from data: NSData
:
let data: NSData = ...
if let str = String(data: data, encoding: NSUTF8StringEncoding) {
print(str)
} else {
print("not a valid UTF-8 sequence")
}
Previous answer:
String
does not have a stringWithBytes()
method.
NSString
has a
NSString(bytes: , length: , encoding: )
method which you could use, but you can create the string directly from NSData
, without the need for an UInt8
array:
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
println(str)
} else {
println("not a valid UTF-8 sequence")
}
Solution 2 - Arrays
Swifty solution
array.reduce("", combine: { $0 + String(format: "%c", $1)})
Hex representation:
array.reduce("", combine: { $0 + String(format: "%02x", $1)})
Solution 3 - Arrays
Update for Swift 5.2.2:
String(decoding: yourByteArray, as: UTF8.self)
Solution 4 - Arrays
This worked for me:
String(bytes: bytes, encoding: NSUTF8StringEncoding)
Solution 5 - Arrays
This solution works.
NSString(bytes: data!, length: data!.count, encoding: NSUTF8StringEncoding)
Solution 6 - Arrays
Swift 3
the following was giving me an error because of "NSUTF8StringEncoding":
String(data: nsdata, encoding: NSUTF8StringEncoding)!
this worked for me in swift 3:
let xmlStr:String = String(bytes: data!, encoding: String.Encoding.utf8)!
Solution 7 - Arrays
For anyone who cannot transform array of bytes to a String, try this
String(data: Data(decrypted), encoding: .utf8)
This is my example string extension. I use it for AES
extension String {
func decryptAES(key: String, iv: String) -> String {
do {
let encrypted = self
let key = Array(key.utf8)
let iv = Array(iv.utf8)
let aes = try AES(key: key, blockMode: CTR(iv: iv), padding: .noPadding)
let decrypted = try aes.decrypt(Array(hex: encrypted))
return String(data: Data(decrypted), encoding: .utf8) ?? ""
} catch {
return "Error: \(error)"
}
}
}
Solution 8 - Arrays
Martin R in https://stackoverflow.com/a/29644387/2214832 answered Sunil Kumar on his problem but not on the topic question. The problem still appears if you already have UInt8 byte array and need to present it as string.
Here is my solution:
extension String {
init(_ bytes: [UInt8]) {
self.init()
for b in bytes {
self.append(UnicodeScalar(b))
}
}
}
Using this extension you can now init String with UInt8 byte array like that:
func testStringUInt8Extension() {
var cs : [UInt8] = []
for char : UInt8 in 0..<255 {
cs.append(char)
}
print("0..255 string looks like \(String(cs)))")
}
This is not ideal solution because practically you would need to decode something like UTF-8 encoded text. But for ASCII data this works as expected.
Solution 9 - Arrays
Here is some more generalized code for extracting strings from a byte array where the strings have been encoded in UTF-8.
/// Class which encapsulates a Swift byte array (an Array object with elements of type UInt8) and an
/// index into the array.
open class ByteArrayAndIndex {
private var _byteArray : [UInt8]
private var _arrayIndex = 0
public init(_ byteArray : [UInt8]) {
_byteArray = byteArray;
}
/// Method to get a UTF-8 encoded string preceded by a 1-byte length.
public func getShortString() -> String {
return getTextData(getUInt8AsInt())
}
/// Method to get a UTF-8 encoded string preceded by a 2-byte length.
public func getMediumString() -> String {
return getTextData(getUInt16AsInt())
}
/// Method to get a UTF-8 encoded string preceded by a 4-byte length. By convention a length of
/// -1 is used to signal a String? value of nil.
public func getLongString() -> String? {
let encodedLength = getInt32()
if encodedLength == -1 {
return nil
}
return getTextData(Int(encodedLength))
}
/// Method to get a single byte from the byte array, returning it as an Int.
public func getUInt8AsInt() -> Int {
return Int(getUInt8())
}
/// Method to get a single byte from the byte array.
public func getUInt8() -> UInt8 {
let returnValue = _byteArray[_arrayIndex]
_arrayIndex += 1
return returnValue
}
/// Method to get a UInt16 from two bytes in the byte array (little-endian), returning it as Int.
public func getUInt16AsInt() -> Int {
return Int(getUInt16())
}
/// Method to get a UInt16 from two bytes in the byte array (little-endian).
public func getUInt16() -> UInt16 {
let returnValue = UInt16(_byteArray[_arrayIndex]) |
UInt16(_byteArray[_arrayIndex + 1]) << 8
_arrayIndex += 2
return returnValue
}
/// Method to get an Int32 from four bytes in the byte array (little-endian).
public func getInt32() -> Int32 {
return Int32(bitPattern: getUInt32())
}
/// Method to get a UInt32 from four bytes in the byte array (little-endian).
public func getUInt32() -> UInt32 {
let returnValue = UInt32(_byteArray[_arrayIndex]) |
UInt32(_byteArray[_arrayIndex + 1]) << 8 |
UInt32(_byteArray[_arrayIndex + 2]) << 16 |
UInt32(_byteArray[_arrayIndex + 3]) << 24
_arrayIndex += 4
return returnValue
}
// Method to decode UTF-8 encoded text data in the byte array.
private func getTextData(_ numberBytes : Int) -> String {
if numberBytes == 0 {
return "" // Tiny optimization?
}
let startIndex = _arrayIndex
_arrayIndex += numberBytes
return String(bytes: _byteArray[startIndex ..< _arrayIndex], encoding: String.Encoding.utf8)!
}
}
This is an extract from a larger class (see also https://stackoverflow.com/a/41547936/253938 ) which I use to process serialized data.
Solution 10 - Arrays
Not very elegant or 'Swifty', but this is simple and it works:
let i: UInt8 = 65
let s = String(format: "%c", i) // A
I wasted hours searching for an easy way to do this, before I suddenly thought of 'printf' from my Unix scripting days!
Solution 11 - Arrays
Complete example for Swift 2 & 3:
import Foundation
let bytes : [UInt8] = [72, 73]
let nsdata = NSData(bytes: bytes as [UInt8], length: 2)
let str = String(data: nsdata, encoding: NSUTF8StringEncoding)! // 'HI'
Solution 12 - Arrays
"MSString(bytes: , length: , encoding: )" does not appear to be working as of July 26th, 2015
Converting byte values to ASCII seems problematic, if you have hit a wall you can do it the hard way as follows (and maybe I am missing something with swift but I couldn't find any solutions within my timeframe.) This will be done with two functions. The first function accepts a UInt8 and converts that to a "\u{}" representation, which is then returned by the function. Second, another function is set up which takes in a UInt8 array as a parameter, then outputs a string.
Step #1. Function convert each byte to "\u{someNumber}"
func convertToCharacters(#UInt8Bits : UInt8) -> String {
var characterToReturn : String
switch UInt8Bits{
case 0x00: characterToReturn = "\u{0}"
case 0x01: characterToReturn = "\u{1}"
case 0x02: characterToReturn = "\u{2}"
case 0x03: characterToReturn = "\u{3}"
case 0x04: characterToReturn = "\u{4}"
//.. Add for as many characters as you anticipate...don't forget base 16..
case 0x09: characterToReturn = "\u{09}"
case 0x0A: characterToReturn = "\u{0A}"
default: characterToReturn = "\u{0}"
/*.. and all the way up to 0xff */
case 0xFE: characterToReturn = "\u{FE}"
case 0xFF: characterToReturn = "\u{FF}"
}
return characterToReturn
}
Step #2 ...Next a function which takes in a UInt8 array as a parameter then returns a string...
func UInt8ArrayToString(#UInt8Array: [UInt8]) -> String {
var returnString : String = ""
for eachUInt8Byte in UInt8Array {
returnString += convertToCharacter(UInt8Bits: eachUInt8Byte)
}
return returnString
}
This should work in a Swift Playground Make an array
var myArray : [UInt8] = [0x30, 0x3A, 0x4B]
//Then apply the functions above
println(UInt8ArrayToString(UInt8Array: myArray))
Solution 13 - Arrays
Swift 4 / Ubuntu 16.04
let serverAns = [UInt8](repeating: 0x50, count: 100)
let readBytes = 8
let truncatedServerAns = serverAns[0..<readBytes]
let tsaData = Data(bytes: truncatedServerAns)
let serverIdStr = String(data: tsaData, encoding: .utf8)
print("serverIdStr=\(String( describing: serverIdStr))")
// Prints:
// serverIdStr=Optional("PPPPPPPP")
Solution 14 - Arrays
You need convert Int8 array to Data firstly, then convert to String.
This is my solution:
var buffer = [Int8](repeating: 0, count: 100)
let data = Data(bytes: buffer as [Int8], count: buffer.count);
return String( data: data, encoding: .utf8)