How to convert a numeric character reference to a decimal in Swift? - swift

How to convert this type of string "8.37" to its decimal value 8.37?
I'm using Swift 4.
I tried:
extension String {
func hexToFloat() -> Float {
var toInt = Int32(truncatingIfNeeded: strtol(self, nil, 16))
var float:Float32!
memcpy(&float, &toInt, MemoryLayout.size(ofValue: float))
return float
}
}
[...]
let myString = "8.37"
let myDecimal = myString.hexToFloat()
print(myDecimal) // prints 0.0
(From here)

There's no straight forward way (at least to my knowledge). But you can do something like below to get the value. Please note that the code below is in Swift 3. You may have to change the syntax.
extension String {
func hexToFloat() -> Float {
let data = myString.data(using: .utf8)
let options: [String: Any] = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
do {
let attributedString = try NSAttributedString(data: data!, options: options, documentAttributes: nil)
return Float(attributedString.string)!
} catch {
return 0
}
}
}
let myString = "8.37"
let myDecimal = myString.hexToFloat()
print(myDecimal) // prints 8.37

Related

Decoding Base64 in Swift Returns nil

I have been trying to implement Coinbase API in my application that is built using swift 5 and xcode. Whenever I try to convert this base64 encoded data to Normal string, it returns nil.
Here is the string
fI5GtCKFF+O8j8uJlJVGxIvolVUUrVMT9GBouxlpEOUXmaGbwQvHt0z8kK0fUwQaKa45KUOLWHP/CQaM70bhdQ==
Below are the answers i've tried
extension String {
func base64Encoded() -> String? {
return data(using: .utf8)?.base64EncodedString()
}
func base64Decoded() -> String? {
var st = self;
print(st.count)
let remainder = self.count % 4
if remainder > 0 {
st = self.padding(toLength: self.count + 4 - remainder,
withPad: "=",
startingAt: 0)
}
print(st.count)
guard let d = Data(base64Encoded: st, options: .ignoreUnknownCharacters) else{
return nil
}
return String(data: d, encoding: .utf8)
}
}
THE DIFFERENCE
let base64Decoded = Data(base64Encoded: "fI5GtCKFF+O8j8uJlJVGxIvolVUUrVMT9GBouxlpEOUXmaGbwQvHt0z8kK0fUwQaKa45KUOLWHP/CQaM70bhdQ==")!
let sign = HMAC.sign(data: "1".toData()!, algorithm: .sha256, key: base64Decoded)
let signData = sign.base64EncodedString()
The result i receive: vBZ+Z63rFqNmU61yrd91PGQB8f1iqocWkLlAev5XJOc=
It's different from: https://www.liavaag.org/English/SHA-Generator/HMAC/
Link to result There's is the correct output. What am i missing or doing wrong ?

JSON parsing float in swift4.1 has unexpected behaviour

A simple function that parse json variable and returns a float.
func parseMyFloat(jsonString: String) -> Float? {
if let data = jsonString.data(using: String.Encoding.utf8, allowLossyConversion: true),
let parsedJSON = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as? [String : Any] {
if let parsedJSON = parsedJSON {
return parsedJSON["myFloat"] as? Float
}
}
return nil
}
Now if i try this.
print(parseMyFloat(jsonString: "{\"myFloat\":23.2322998046875}"))
// output: 23.2322998
output is fine but if I change 23.2322998046875 value to 23.2322998046 func returns nil.
print(parseMyFloat(jsonString: "{\"myFloat\":23.2322998}"))
// output: nil
Then I tried casting Any to Float which doesn't work.
let dic:[String : Any] = ["float1" : 23.2322998046875, "float2" : 23.2322998]
print(dic["float1"] as? Float) // prints nil
print(dic["float2"] as? Float) // prints nil
I have lots of float in my code, so after migrating to swift 4.1 I am having this issue.
Should I change all Float's to Double's ?? And 23.2322998046875 why works and why not 23.2322998??
If you want to keep your function as it is and don't want to modify the return value to Double, you can simply parse the JSON value as Double to avoid the issue of casting Any to Float as explained in the comments and then convert the Double to Float before returning it.
func parseMyFloat(jsonString: String) -> Float? {
if let data = jsonString.data(using: String.Encoding.utf8, allowLossyConversion: true), let parsedJSON = (try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments)) as? [String : Any], let myDouble = parsedJSON["myFloat"] as? Double {
return Float(myDouble)
}
return nil
}
parseMyFloat(jsonString: "{\"myFloat\":23.2322998046875}") //23.2323998
parseMyFloat(jsonString: "{\"myFloat\":23.2322998}") //23.2323998

distance(from:to:)' is unavailable: Any String view index conversion can fail in Swift 4; please unwrap the optional indices

I was trying to migrate my app to Swift 4, Xcode 9. I get this error. Its coming from a 3rd party framework.
distance(from:to:)' is unavailable: Any String view index conversion can fail in Swift 4; please unwrap the optional indices
func nsRange(from range: Range<String.Index>) -> NSRange {
let utf16view = self.utf16
let from = range.lowerBound.samePosition(in: utf16view)
let to = range.upperBound.samePosition(in: utf16view)
return NSMakeRange(utf16view.distance(from: utf16view.startIndex, to: from), // Error: distance(from:to:)' is unavailable: Any String view index conversion can fail in Swift 4; please unwrap the optional indices
utf16view.distance(from: from, to: to))// Error: distance(from:to:)' is unavailable: Any String view index conversion can fail in Swift 4; please unwrap the optional indices
}
You can simply unwrap the optional indices like this:
func nsRange(from range: Range<String.Index>) -> NSRange? {
let utf16view = self.utf16
if let from = range.lowerBound.samePosition(in: utf16view), let to = range.upperBound.samePosition(in: utf16view) {
return NSMakeRange(utf16view.distance(from: utf16view.startIndex, to: from), utf16view.distance(from: from, to: to))
}
return nil
}
The error says that the distances you are generating are optionals and need to be unwrapped. Try this:
func nsRange(from range: Range<String.Index>) -> NSRange {
let utf16view = self.utf16
guard let lowerBound = utf16view.distance(from: utf16view.startIndex, to: from), let upperBound = utf16view.distance(from: from, to: to) else { return NSMakeRange(0, 0) }
return NSMakeRange(lowerBound, upperBound)
}
However the return could be handled better in the guard statement. I'd recommend making the return type of the function NSRange? and checking for nil wherever you call the function to avoid inaccurate values being returned.
Please check :
let dogString = "Dog‼🐶"
let range = dogString.range(of: "🐶")!
// This is using Range
let strRange = dogString.range(range: range)
print((dogString as NSString).substring(with: strRange!)) // 🐶
extension String {
func range(range : Range<String.Index>) -> NSRange? {
let utf16view = self.utf16
guard
let from = String.UTF16View.Index(range.lowerBound, within: utf16view),
let to = String.UTF16View.Index(range.upperBound, within: utf16view)
else { return nil }
let utf16Offset = utf16view.startIndex.encodedOffset
let toOffset = to.encodedOffset
let fromOffset = from.encodedOffset
return NSMakeRange(fromOffset - utf16Offset, toOffset - fromOffset)
}
}
// This is using NSRange
let strNSRange = dogString.range(nsRange: NSRange(range, in: dogString))
print((dogString as NSString).substring(with: strNSRange!)) // 🐶
extension String {
func range(nsRange: NSRange) -> NSRange? {
guard
let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex),
let to16 = utf16.index(utf16.startIndex, offsetBy: nsRange.length, limitedBy: utf16.endIndex),
let from = from16.samePosition(in: self),
let to = to16.samePosition(in: self)
else { return nil }
return NSMakeRange(from.encodedOffset, to.encodedOffset)
}
}

Hex string to text conversion - swift 3

I'm trying to convert an hex string to text.
This is what i have:
// Str to Hex
func strToHex(text: String) -> String {
let hexString = text.data(using: .utf8)!.map{ String(format:"%02x", $0) }.joined()
return "0x" + hexString
}
and I'm trying to reverse the hex string that I've just created back to the original one.
So, for example:
let foo: String = strToHex(text: "K8") //output: "0x4b38"
and i would like to do something like
let bar: String = hexToStr(hex: "0x4b38") //output: "K8"
can someone help me?
Thank you
You probably can use something like this:
func hexToStr(text: String) -> String {
let regex = try! NSRegularExpression(pattern: "(0x)?([0-9A-Fa-f]{2})", options: .caseInsensitive)
let textNS = text as NSString
let matchesArray = regex.matches(in: textNS as String, options: [], range: NSMakeRange(0, textNS.length))
let characters = matchesArray.map {
Character(UnicodeScalar(UInt32(textNS.substring(with: $0.rangeAt(2)), radix: 16)!)!)
}
return String(characters)
}
NSRegularExpression is overkill for the job. You can convert the string to byte array by grabbing two characters at a time:
func hexToString(hex: String) -> String? {
guard hex.characters.count % 2 == 0 else {
return nil
}
var bytes = [CChar]()
var startIndex = hex.index(hex.startIndex, offsetBy: 2)
while startIndex < hex.endIndex {
let endIndex = hex.index(startIndex, offsetBy: 2)
let substr = hex[startIndex..<endIndex]
if let byte = Int8(substr, radix: 16) {
bytes.append(byte)
} else {
return nil
}
startIndex = endIndex
}
bytes.append(0)
return String(cString: bytes)
}
Solution that supports also special chars like emojis etc.
static func hexToPlain(input: String) -> String {
let pairs = toPairsOfChars(pairs: [], string: input)
let bytes = pairs.map { UInt8($0, radix: 16)! }
let data = Data(bytes)
return String(bytes: data, encoding: .utf8)!
}

Convert string to base64 in Swift 3

let strsize = 10_000_000
let tries = 100
var longstring:String = "a"
for i in 1...strsize {
longstring += "a"
}
for i in 1..<2 {
let basestring = NSData(base64EncodedString: longstring, options: .IgnoreUnknownCharacters)
print(basestring)
}
Writing a code in command prompt. What is the correct code to write for Swift 3 which I been getting use of unresolved identifier NSData . Most of the tutorials on encoding string to base64 aren't working.
This is working for you on Linux or Mac?
http://studyswift.blogspot.sg/2016/03/convert-nsdatauint8-to-base64-in-swift.html
Use this instead:
let longstring = "test123"
if let data = (longstring).data(using: String.Encoding.utf8) {
let base64 = data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0))
print(base64)// dGVzdDEyMw==\n
}
this string extention can help .
extension String {
//Base64 decode
func fromBase64() -> String? {
guard let data = Data(base64Encoded: self) else {
return nil
}
return String(data: data, encoding: .utf8)
}
//Base64 encode
func toBase64() -> String {
return Data(self.utf8).base64EncodedString()
}
}
how to use.
let str = "Hello World"
str.toBase64().fromBase64()
In Swift 4.2 and Xcode 10.1
//Base64 encoding
let data = combinedString.data(using: .utf8)//Here combinedString is your string
let encodingString = data?.base64EncodedString()
print(encodingString!)
// OR Single line of code
let encodingString = combinedString.data(using: .utf8)?.base64EncodedString()//Here combinedString is your string
print(encodingString!)