How Can I convert byte array to String in Swift - arrays

I have a json as below. I need to convert the image to a byte array and post it as a String.
I can convert the image to byte array but how can I convert it to String?
I am getting an error while converting byte array to String.
Error:
"not a valid UTF-8 sequence"
JSON:
"photo1": "[255,216,255,224,0,16,74,70,73, ..... ,]"
Image Data to Byte Array:
func getArrayOfBytesFromImage(imageData:NSData) -> Array<UInt8> {
// the number of elements:
let count = imageData.length / MemoryLayout<Int8>.size
// create array of appropriate length:
var bytes = [UInt8](repeating: 0, count: count)
// copy bytes into array
imageData.getBytes(&bytes, length:count * MemoryLayout<Int8>.size)
var byteArray:Array = Array<UInt8>()
for i in 0 ..< count {
byteArray.append(bytes[i])
}
return byteArray
}
Using getArrayOfBytesFromImage Function:
if let string = String(bytes: getArrayOfBytesFromImage(imageData: imageData), encoding: .utf8) {
print(string)
} else {
print("not a valid UTF-8 sequence")
}

Those are not UTF-8 bytes, so don't say encoding: .utf8. Those bytes do not form a string, so you should not use String.init(bytes:encoding:). You should get the value of those bytes, and get their description one way or another (e.g. by string interpolation).
You don't even need a byte array here. Just go straight to strings, since that's what you're after.
let imageData = Data([1, 2, 3, 4, 5]) // for example
let string = "[\(imageData.map { "\($0)" }.joined(separator: ","))]"
print(string) // prints [1,2,3,4,5]

Related

Convert [MLMultiArray] to Float?

I have an MLMultiArray which is a result of an ML Model.
I need to convert it to Float so that I can further store it in Realm.
Below is an example of one of the MLMultiArray. The result from the ML Model contains 120 of the same vectors so its an array of MLMultiArrays i.e Array of Float32 1 x 128 matrices.
Float32 1 x 128 matrix
[4.476562,1.179688,0.07141113,6.976562,-0.2858887,-7.378906,0.6445312,3.695312,1.399414,2.486328,-3.988281,-0.2636719,1.000977,-4.480469,-7.832031,1.59082,0.8515625,-1.296875,-1.435547,7.839844,5.851562,0.3701172,-2.492188,7.273438,2.404297,-3.3125,-5.699219,-0.6816406,0.2807617,-3.882812,-3.982422,5.339844,4.125,-3.871094,0.6225586,1.712891,-10.02344,0.7119141,4.472656,3.566406,-0.559082,-1.049805,-4.679688,10.07812,-1.459961,4.707031,-6.078125,1.675781,-0.6259766,2.519531,3.472656,-3.400391,-6.714844,-4.933594,-1.733398,1.095703,-6.15625,9.234375,3.693359,-9.492188,0.8637695,0.8203125,-2.814453,-4.4375,-1.092773,3.332031,0.1623535,3.583984,-11.25781,-0.9941406,-0.3491211,1.464844,-1.579102,4.558594,2.703125,4.601562,5.914062,-2.402344,-5.46875,-0.355957,11.39062,2.070312,-7.289062,-0.4470215,-0.1595459,9.148438,1.833008,-2.097656,-3.9375,6.699219,-4.347656,-6.835938,-1.179688,3.910156,-13.07812,-1.947266,-0.9238281,-0.949707,-4.398438,2.363281,4.421875,4.632812,2.607422,8.773438,0.9106445,9.21875,-14.0625,-1.301758,-4.875,0.6054688,6.496094,-2.021484,3.898438,-4.644531,0.9853516,7.253906,3.066406,-1.051758,-8.09375,-6.527344,3.890625,5.175781,0.3701172,-0.5683594,-1.341797,0.1497803,4.074219,0.5932617]
Is there any way I can convert an array of MLMultiArray to Float32?
Any help would be appreciated <3
You can first convert the MLMultiArray to an UnsafeBufferPointer and then to a regular Array.
import CoreML
var a: [Float] = [ 1, 2, 3 ]
var m = try! MLMultiArray(a)
if let b = try? UnsafeBufferPointer<Float>(m) {
let c = Array(b)
print(c)
}
This is old question but this can help someone:
To convert from an MLMultiArray To An Array of primitive, You can use this function you will need just to change the output type
func convertToArray(from mlMultiArray: MLMultiArray) -> [Double] {
// Init our output array
var array: [Double] = []
// Get length
let length = mlMultiArray.count
// Set content of multi array to our out put array
for i in 0...length - 1 {
array.append(Double(truncating: mlMultiArray[[0,NSNumber(value: i)]]))
}
return array
}
To convert from an Array to MLMultiArray Use this, you may need to change the shape accordingly
func convertToMLMultiArray(from array: [Double]) -> MLMultiArray {
let length = NSNumber(value: array.count)
// Define shape of array
guard let mlMultiArray = try? MLMultiArray(shape:[1, length], dataType:MLMultiArrayDataType.double) else {
fatalError("Unexpected runtime error. MLMultiArray")
}
// Insert elements
for (index, element) in array.enumerated() {
mlMultiArray[index] = NSNumber(floatLiteral: element)
}
return mlMultiArray
}
I'm using this way, and subscript to access the element and it works fine for me.
const float *array = (float*)matrix.dataPointer

swift - corebluetooth writing 2 bytes

I getting a text input and writing it to a ble device. I don't have an issue for 1 Byte of data but I could not covert the text input value to 2 bytes and send it.
How can I convert a value like 3400 to 2 bytes of UInt8 array and what should I for values below 255?
For 1 byte I use:
let myInt = Int(textField.text)
let value: [UInt8] = [UInt8(myInt)]
self.bluetoothManager.writeValue(data: Data(bytes: value), forCharacteristic: myChar!, type: .withResponse)
I tried to convert like this but I can't send String with .writeValue:
https://stackoverflow.com/a/36967037/4704055
let d1 = 21
let b1 = String(d1, radix: 2)
print(b1) // "10101"
You probably want to convert the string to a 16-bit integer, then
convert the integer to data (compare round trip Swift number types to/from Data), and finally write the data to the device:
guard var value = Int16(textField.text) else {
// ... invalid number ...
}
// value = value.bigEndian (if big-endian is expected by the device)
let data = Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
self.bluetoothManager.writeValue(data: data, ...)

Convert string of coordinates into an array of CLLocations in Swift

I have a string with a list of coordinates that I need to convert into an array. I tried to do let array = Array(coordinates) but it says String no longer conforms to SequenceType. I need to convert the string to an array of CLLocations. The string I am trying to convert looks like this:
let coordinates = "[[39.86475483576405,-75.53281903266907], [39.864688955564304,-75.53292632102966], [39.86455719497505,-75.53300142288208], [39.86440072894666,-75.5330228805542], [39.8642689678039,-75.53295850753784], [39.863305456757146,-75.53223967552185], [39.86303369478483,-75.53266882896423]]"
The string is a valid JSON string.
The most straightforward way is to deserialize the string with JSONSerialization and map the result to [CLLocation]
let coordinates = "[[39.86475483576405,-75.53281903266907], [39.864688955564304,-75.53292632102966], [39.86455719497505,-75.53300142288208], [39.86440072894666,-75.5330228805542], [39.8642689678039,-75.53295850753784], [39.863305456757146,-75.53223967552185], [39.86303369478483,-75.53266882896423]]"
if let data = coordinates.data(using: .utf8),
let jsonArray = try? JSONSerialization.jsonObject(with: data) as? [[Double]] {
let locationArray = jsonArray!.map{CLLocation(latitude:$0[0], longitude:$0[1]) }
print(locationArray)
}
One approach would be to strip all of the brackets and spaces and then split the comma separated numbers into an array. Then convert each pair of number strings into numbers and finally create a CLLocation from the pair of numbers.
// Your string
let coordinates = "[[39.86475483576405,-75.53281903266907], [39.864688955564304,-75.53292632102966], [39.86455719497505,-75.53300142288208], [39.86440072894666,-75.5330228805542], [39.8642689678039,-75.53295850753784], [39.863305456757146,-75.53223967552185], [39.86303369478483,-75.53266882896423]]"
// Remove the brackets and spaces
let clean = coordinates.replacingOccurrences(of: "[\\[\\] ]", with: "", options: .regularExpression, range: nil)
// Split the comma separated strings into an array
let values = clean.components(separatedBy: ",")
var coords = [CLLocation]()
for i in stride(from: 0, to: values.count, by: 2) {
// Pull out each pair and convert to Doubles
if let lat = Double(values[i]), let long = Double(values[i+1]) {
let coord = CLLocation(latitude: lat, longitude: long)
coords.append(coord)
}
}

String into array in Swift 3

I am trying to transform a string of the following format into an array (...of arrays, of floats!) in Swift 3:
"[173.0, 180.5],[173.0, 180.0],[174.0, 180.5],[174.0, 183.0]"
so that the output would be an array in this format:
[[173.0, 180.5, 173.0, 180.0],[174.0, 180.5, 174.0, 183.0]]
I am really new to Swift and struggling to find any String functions that will allow me to convert the data in this way. Any pointers on how I can do it would be awesome - thanks!
As Martin said, you first want to first convert this from a string to an array. In Swift 3:
let string = "[173.0, 180.5],[173.0, 180.0],[174.0, 180.5],[174.0, 183.0]"
let jsonString = "[" + string + "]"
guard let data = jsonString.data(using: .utf8),
let json = try? JSONSerialization.jsonObject(with: data),
let numberPairs = json as? [[Double]] else {
fatalError("string was not well-formed: \(string)")
}
You then want to combine these pairs of numbers together:
var combinedNumbers = [[Double]]()
var current: [Double]?
for numberPair in numberPairs {
if current != nil {
combinedNumbers.append(current! + numberPair)
current = nil
} else {
current = numberPair
}
}
// use `combinedNumbers` here
Clearly, you should use better variable names (perhaps something that suggests what these sets of numbers are), but hopefully this illustrates the idea.
Swift 4
You can use Decodable:
let str = "[173.0, 180.5],[173.0, 180.0],[174.0, 180.5],[174.0, 183.0]"
let json = "[\(str)]".data(using: .utf8)!
let numbers = try JSONDecoder().decode([[Double]].self, from: json).flatMap { $0 }
let result = stride(from: 0, to: numbers.count, by: 4).map { startIndex -> [Double] in
let endIndex = min(startIndex + 4, numbers.count)
return Array(numbers[startIndex..<endIndex])
}
Swift 3
One option is to use the old-school NSScanner to extract the numbers from the string to a flat array, then build a 2 dimensional array off that:
let str = "[173.0, 180.5],[173.0, 180.0],[174.0, 180.5],[174.0, 183.0]"
let scanner = Scanner(string: str)
scanner.charactersToBeSkipped = CharacterSet(charactersIn: "[], ")
// Build the flat array
var numbers = [Double]()
while !scanner.isAtEnd {
var d = 0.0
if scanner.scanDouble(&d) {
numbers.append(d)
}
}
// Now the 2 dimensional array
let result = stride(from: 0, to: numbers.count, by: 4).map { startIndex -> [Double] in
let endIndex = min(startIndex + 4, numbers.count)
return Array(numbers[startIndex..<endIndex])
}
One option to convert the data types would be to develop a simple algorithm that will iterate through the string and analyze elements and square bracket delimiters, returning the appropriate conversion.
Below is the skeleton of what the fundamental components of such a function could look like.
Included are some basic aspects of the conversion from string to array.
var str = "[173.0, 180.5], [173.0, 180.0],[174.0, 180.5],[174.0, 183.0]"
// Cast returns array ["[","1","7","3",".","0",",".......]
let array = Array(str.characters)
// Iterate through array
for char in array {
if char == "[" || char == "]" {
// Deal with array delimiters appropriately
}
...
}
It might help to check out this similar problem.
NOTE: As Martin R mentioned, JSON interpretation may be a good method as well.

How to convert a String (numeric) in a Int array in Swift

I'd like to know how can I convert a String in an Int array in Swift.
In Java I've always done it like this:
String myString = "123456789";
int[] myArray = new int[myString.lenght()];
for(int i=0;i<myArray.lenght;i++){
myArray[i] = Integer.parseInt(myString.charAt(i));
}
Thanks everyone for helping!
let str = "123456789"
let intArray = map(str) { String($0).toInt() ?? 0 }
map() iterates Characters in str
String($0) converts Character to String
.toInt() converts String to Int. If failed(??), use 0.
If you prefer for loop, try:
let str = "123456789"
var intArray: [Int] = []
for chr in str {
intArray.append(String(chr).toInt() ?? 0)
}
OR, if you want to iterate indices of the String:
let str = "123456789"
var intArray: [Int] = []
for i in indices(str) {
intArray.append(String(str[i]).toInt() ?? 0)
}
You can use flatMap to convert the characters into a string and coerce the character strings into an integer:
Swift 2 or 3
let string = "123456789"
let digits = string.characters.flatMap{Int(String($0))}
print(digits) // [1, 2, 3, 4, 5, 6, 7, 8, 9]"
Swift 4
let string = "123456789"
let digits = string.flatMap{Int(String($0))}
print(digits) // [1, 2, 3, 4, 5, 6, 7, 8, 9]"
Swift 4.1
let digits = string.compactMap{Int(String($0))}
Swift 5 or later
We can use the new Character Property wholeNumberValue https://developer.apple.com/documentation/swift/character/3127025-wholenumbervalue
let digits = string.compactMap{$0.wholeNumberValue}
#rintaro's answer is correct, but I just wanted to add that you can use reduce to weed out any characters that can't be converted to an Int, and even display a warning message if that happens:
let str = "123456789"
let intArray = reduce(str, [Int]()) { (var array: [Int], char: Character) -> [Int] in
if let i = String(char).toInt() {
array.append(i)
} else {
println("Warning: could not convert character \(char) to an integer")
}
return array
}
The advantages are:
if intArray contains zeros you will know that there was a 0 in str, and not some other character that turned into a zero
you will get told if there is a non-Int character that is possibly screwing things up.
Swift 3
Int array to String
let arjun = [1,32,45,5]
print(self.get_numbers(array: arjun))
func get_numbers(array:[Int]) -> String {
let stringArray = array.flatMap { String(describing: $0) }
return stringArray.joined(separator: ",")
String to Int Array
let arjun = "1,32,45,5"
print(self.get_numbers(stringtext: arjun))
func get_numbers(stringtext:String) -> [Int] {
let StringRecordedArr = stringtext.components(separatedBy: ",")
return StringRecordedArr.map { Int($0)!}
}
var myString = "123456789"
var myArray:[Int] = []
for index in 0..<countElements(myString) {
var myChar = myString[advance(myString.startIndex, index)]
myArray.append(String(myChar).toInt()!)
}
println(myArray) // [1, 2, 3, 4, 5, 6, 7, 8, 9]"
To get the iterator pointing to a char from the string you can use advance
The method to convert string to int in Swift is toInt()
Swift 3 update:
#appzYourLife : That's correct toInt() method is no longer available for String in Swift 3.
As an alternative what you can do is :
intArray.append(Int(String(chr)) ?? 0)
Enclosing it within Int() converts it to Int.
Swift 3: Functional Approach
Split the String into separate String instances using:
components(separatedBy separator: String) -> [String]
Reference: Returns an array containing substrings from the String that have been divided by a given separator.
Use the flatMap Array method to bypass the nil coalescing while converting to Int
Reference: Returns an array containing the non-nil results of calling the given transformation with each element of this sequence.
Implementation
let string = "123456789"
let intArray = string.components(separatedBy: "").flatMap { Int($0) }
let array = "0123456789".compactMap{ Int(String($0)) }
print(array)

Resources