0

I am getting this below string as a response from WS API when they send emoji as a string:

let strTemp = "Hii \\xF0\\x9F\\x98\\x81"

I want it to be converted to the emoji icon like this -> Hii

I think so it is coming in UTF-8 Format as explained in the below Image: Image Unicode enter image description here

I have tried decoding it Online using UTF-8 Decoder

And i got the emoticon Successfully decoded

Before Decoding:

enter image description here

After Decoding: enter image description here

But the issue here is I do not know how to work with it in Swift.

I referred following link but it did not worked for me.

Swift Encode/decode emojis

Any help would be appreciated.

Thanks.

Abhirajsinh Thakore
  • 1,806
  • 2
  • 13
  • 23

2 Answers2

1

As you already given the link of converter tool which is clearly doing UTF-8 encoding and decoding. You have UTF-8 encoded string so here is an example of UTF8-Decoding.

Objective-C

const char *ch = [@"Hii \xF0\x9F\x98\x81" cStringUsingEncoding:NSUTF8StringEncoding];
NSString *decode_string = [NSString stringWithUTF8String:ch];
NSLog(@"%@",decode_string);

Output: Hii


Swift

I'm able to convert \\xF0\\x9F\\x98\\x81 to in SWift. First I converted the hexa string into Data and then back to String using UTF-8 encoding.

var str = "\\xF0\\x9F\\x98\\x81"
if let data = data(fromHexaStr: str) {
     print(String(data: data, encoding: String.Encoding.utf8) ?? "")
}

Output:

Below is the function I used to convert the hexa string into data. I followed this answer.

func data(fromHexaStr hexaStr: String) -> Data? {
    var data = Data(capacity: hexaStr.characters.count / 2)
    let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
    regex.enumerateMatches(in: hexaStr, range: NSMakeRange(0, hexaStr.utf16.count)) { match, flags, stop in
        let byteString = (hexaStr as NSString).substring(with: match!.range)
        var num = UInt8(byteString, radix: 16)!
        data.append(&num, count: 1)
    }

    guard data.count > 0 else { return nil }

    return data
}

Note: Problem with above code is it converts hexa string only not combined strings.

FINAL WORKING SOLUTION: SWIFT

I have done this by using for loop instead of [0-9a-f]{1,2} regex because this will also scan 81, 9F, Any Two digits number which is wrong obviously.

For example: I have 81 INR \\xF0\\x9F\\x98\\x81.

/// This line will convert "F0" into hexa bytes
let byte = UInt8("F0", radix: 16)

I made a String extension in which I check upto every 4 characters if it has prefix \x and count 4 and last two characters are convertible into hexa bytes by using radix as mentioned above.

extension String {

    func hexaDecoededString() -> String {

        var newData = Data()
        var emojiStr: String = ""
        for char in self.characters {

            let str = String(char)
            if str == "\\" || str.lowercased() == "x" {
                emojiStr.append(str)
            }
            else if emojiStr.hasPrefix("\\x") || emojiStr.hasPrefix("\\X") {
                emojiStr.append(str)
                if emojiStr.count == 4 {
                    /// It can be a hexa value
                    let value = emojiStr.replacingOccurrences(of: "\\x", with: "")
                    if let byte = UInt8(value, radix: 16) {
                        newData.append(byte)
                    }
                    else {
                        newData.append(emojiStr.data(using: .utf8)!)
                    }
                    /// Reset emojiStr
                    emojiStr = ""
                }
            }
            else {
                /// Append the data as it is
                newData.append(str.data(using: .utf8)!)
            }
        }

        let decodedString = String(data: newData, encoding: String.Encoding.utf8)
        return decodedString ?? ""
    }
}

USAGE:

var hexaStr = "Hi \\xF0\\x9F\\x98\\x81 81"
print(hexaStr.hexaDecoededString())

Hi 81

hexaStr = "Welcome to SP19!\\xF0\\x9f\\x98\\x81"
print(hexaStr.hexaDecoededString())

Welcome to SP19!

TheTiger
  • 13,264
  • 3
  • 57
  • 82
1

I fix your issue but it need more work to make it general , the problem here is that your Emijo is Represented by Hex Byte x9F , so we have to convert this Hex to utf8 then convert it to Data and at last convert data to String

Final result Hii Please read comment

 let strTemp = "Hii \\xF0\\x9F\\x98\\x81"


            let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
            // get all matched hex  xF0 , x9f,..etc

            let matches = regex.matches(in: strTemp, options: [], range: NSMakeRange(0, strTemp.count))


            // Data that will hanlde convert hex to UTf8
            var emijoData = Data(capacity: strTemp.count / 2)

            matches.enumerated().forEach { (offset , check) in
                let byteString = (strTemp as NSString).substring(with: check.range)
                var num = UInt8(byteString, radix: 16)!
                emijoData.append(&num, count: 1)
            }

            let subStringEmijo = String.init(data: emijoData, encoding: String.Encoding.utf8)!
            //now we have your emijo text   we can replace by its code from string using matched ranges `first` and `last`

            // All range range of  \\xF0\\x9F\\x98\\x81 in "Hii \\xF0\\x9F\\x98\\x81" to replce by your emijo

            if let start = matches.first?.range.location, let end = matches.last?.range.location  , let endLength = matches.last?.range.length {

                let startLocation = start  - 2
                let length = end - startLocation + endLength

                let sub = (strTemp as NSString).substring(with: NSRange.init(location: startLocation, length: length))

                print( strTemp.replacingOccurrences(of: sub, with: subStringEmijo))
              // Hii 

            }
Abdelahad Darwish
  • 5,969
  • 1
  • 17
  • 35
  • Hello Thanks for the Answer, It helped me a lot, But the thing is it is working for a static string "Hii \\xF0\\x9F\\x98\\x81". What if i get dynamic string in my response. Like "Welcome to SP19!\\xF0\\x9f\\x98\\x81" in this case the emoji is being printed but the app is getting crashed at replacing sub string. any solution to this to making it dynamic.? – Abhirajsinh Thakore May 21 '18 at 06:14
  • App crash is done because `subStringEmijo` is nill check it, this code is general , you just need to refactor it – Abdelahad Darwish May 21 '18 at 08:47
  • The app gets crashed at let sub = (strTemp as NSString).substring(with: NSRange.init(location: startLocation, length: length)). If i get some other string – Abhirajsinh Thakore May 21 '18 at 09:26
  • yes, i told you the idea , you need to configure it , you need to get-all ranges of your encoded emijo and replace by decoded emijo – Abdelahad Darwish May 21 '18 at 09:28
  • Thanks For the Suggestion sir. Have up Voted the Answer for your hard Work. – Abhirajsinh Thakore May 22 '18 at 07:26