Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift - Encoding and Decoding String for special characters

Here is my problem : I'm currently developping an app including an instant chat (using FCM). Every thing works except when i try to send special characters like "é" or emojis. The push notification received contains the good string but when the discussion is saved on the server and then reloaded, I can't read them and get UTF8 text like "u00ea" for "ê". I don't really know a lot about encoding etc. but if you guys could help I would be very happy !

Here is the code i use to send a message :

    func sendMessage(_ completion: @escaping (_ response: String) -> ()) {

    DispatchQueue.global(qos: .userInitiated).async { () -> Void in
        let urlString = //Server adress
        let url = URL(string: urlString)

        var request = URLRequest(url: url!)
        let set = CharacterSet()
        request.httpMethod = "POST"
        let postString = "Message=" + /*String text to send*/
        request.httpBody = postString.data(using: String.Encoding.utf8)

    let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in

        })
        task.resume()
    }
}

Thanks a lot !

PS : I'm new to asking to stackoverflow so don't hesitate to ask for more details

Edit as asked by Rob : I sent the message "test é è".
The other phone received "test é è" via push notification.
When one phone loads discussion from the server where its stored the answer from the server is.

    [{"content":"test u00e9 u00e8","sender":"103","timestamp":"1475491191"}]

Also I'm not coding the server, but the guy who is is also making an android app which works really fine with special characters.

Edit #2 : I also try this code

    var request = URLRequest(url: url!)
        let set = CharacterSet()
        request.httpMethod = "POST"
        let postString = "Message=" + self.message.addingPercentEncoding(withAllowedCharacters: set)!
        let bytesArray = UTF8Encoding.decode(postString)

        request.httpBody = Data(bytes: UnsafePointer<UInt8>(bytesArray), count: bytesArray.count)

It does not make any difference.

Thanks a lot for your help guys.

like image 747
Alexis Semmama Avatar asked Oct 02 '16 15:10

Alexis Semmama


People also ask

How do you escape special characters in Swift?

Swift's escape character is \ , the backslash (U+005C). Escape character sequences (shortened to escape sequence) represent special characters. In the current version of Swift, the backslash escape character tells the compiler that a sequence should combine to produce one of these special characters.

How do I remove special characters from a string in Swift 5?

Swift String – Remove Specific Characters To remove specific set of characters from a String in Swift, take these characters to be removed in a set, and call the removeAll(where:) method on this string str , with the predicate that if the specific characters contain this character in the String.

How do you check if a string contains a character in Swift?

In the Swift string, we check if the specified string is present in a string or not. To do this task we use the contains() function. This function is used to check whether the specified string i.e. sequence of characters is present in the string or not.

What is encoding and decoding in Swift?

But before you can do that, you need to convert the data to a suitable format through a process called encoding or serialization. You'll also need to convert the saved data sent over the network to a suitable format before using it in your app. This reverse process is called decoding or deserialization.


2 Answers

You want to use addingPercentEncoding to percent escape the string. But don't be tempted to use a character set like urlQueryAllowed, as that will let some key characters (notably & and +) pass unescaped.

As a nice example of how to do this properly, see Alamofire's ParameterEncoding escape routine. Here is a rendition implemented as an extension:

extension String {
    public func addingPercentEncodingForQueryParameter() -> String? {
        return addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)
    }
}

extension CharacterSet {
    static let urlQueryValueAllowed: CharacterSet = {
        let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
        let subDelimitersToEncode = "!$&'()*+,;="

        var allowed = CharacterSet.urlQueryAllowed
        allowed.remove(charactersIn: generalDelimitersToEncode + subDelimitersToEncode)

        return allowed
    }()
}

Then you can do something like:

func send(message: String, _ completion: @escaping (_ response: String) -> ()) {
    let urlString = ...
    let url = URL(string: urlString)

    var request = URLRequest(url: url!)
    request.httpMethod = "POST"
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    let postString = "Message=\(message.addingPercentEncodingForQueryParameter()!)"
    request.httpBody = postString.data(using: .utf8)

    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        ...
    }
    task.resume()
}
like image 127
Rob Avatar answered Nov 15 '22 07:11

Rob


Ok so I think I have it,

As suggested, it was due partially to the server implementation. Due to its security it filtered certain characters and that's why it wasn't working.

We have corrected the problem but it's still doesn't work when the discussion is from iOS to Android or Android to iOS.

Thanks a lot for your help !

Here is my final code :

var request = URLRequest(url: url!)
request.httpMethod = "POST"
let postString = "Message=" + (self.message.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed))!
request.httpBody = postString.data(using: String.Encoding.utf8, allowLossyConversion: true)
like image 35
Alexis Semmama Avatar answered Nov 15 '22 06:11

Alexis Semmama