Swift - Encoding and Decoding String for Special Characters

Swift - Encoding and Decoding String for special characters

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)

Decode URLs with special characters in Swift

There are multiple way to overcome this, but I think using a property wrapper is probably the most elegant:

@propertyWrapper
struct URLPercentEncoding {
var wrappedValue: URL
}

extension URLPercentEncoding: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()

if let str = try? container.decode(String.self),
let encoded = str.addingPercentEncoding(
withAllowedCharacters: .urlFragmentAllowed),
let url = URL(string: encoded) {

self.wrappedValue = url

} else {
throw DecodingError.dataCorrupted(
.init(codingPath: container.codingPath, debugDescription: "Corrupted url"))
}
}
}

Then you could use it like so without the consumer of this model having to know anything about it:

struct Response: Decodable {
@URLPercentEncoding let url: URL
}

Encoding Swift string as escaped unicode?

You can use reduce in your collection and check if each character isASCII, if true return that character otherwise convert the special character to unicode:

Swift 5.1 • Xcode 11

extension Unicode.Scalar {
var hexa: String { .init(value, radix: 16, uppercase: true) }
}

extension Character {
var hexaValues: [String] {
unicodeScalars
.map(\.hexa)
.map { #"\\U"# + repeatElement("0", count: 8-$0.count) + $0 }
}
}

extension StringProtocol where Self: RangeReplaceableCollection {
var asciiRepresentation: String { map { $0.isASCII ? .init($0) : $0.hexaValues.joined() }.joined() }
}

let textContainingUnicode = """
Let's go in the .
And some new lines.
"""

let asciiRepresentation = textContainingUnicode.asciiRepresentation
print(asciiRepresentation) // "Let's go \\U0001F3CA in the \\U0001F30A.\n And some new lines."

Converting any UTF-8 encoded Characters in String in Swift from API

You can use NSAttributedString to convert these HTML entities to string.

let htmlString = "test北京的test"
if let htmldata = htmlString.dataUsingEncoding(NSUTF8StringEncoding), let attributedString = try? NSAttributedString(data: htmldata, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) {
let finalString = attributedString.string
print(finalString)
//output: test北京的test
}

How to know if a string is already escaped special with special characters?

you can do it smoothly:

extension String {
func isEscaped() -> Bool {
return self.removingPercentEncoding != self
}
}

then

let yourEscapedString = "http://www.somedomain.com/folder/%D9%85%D8%B1%D8%AD%D8%A8%D8%A7%20%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85.jpg"
print(yourEscapedString.isEscaped()) // true

let yourNotEscapedString = "http://www.somedomain.com/folder/مرحبا المستخدم.jpg"
print(yourNotEscapedString.isEscaped()) // false

How do I decode HTML entities in Swift?

This answer was last revised for Swift 5.2 and iOS 13.4 SDK.


There's no straightforward way to do that, but you can use NSAttributedString magic to make this process as painless as possible (be warned that this method will strip all HTML tags as well).

Remember to initialize NSAttributedString from main thread only. It uses WebKit to parse HTML underneath, thus the requirement.

// This is a[0]["title"] in your case
let htmlEncodedString = "The Weeknd <em>‘King Of The Fall’</em>"

guard let data = htmlEncodedString.data(using: .utf8) else {
return
}

let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue
]

guard let attributedString = try? NSAttributedString(data: data, options: options, documentAttributes: nil) else {
return
}

// The Weeknd ‘King Of The Fall’
let decodedString = attributedString.string
extension String {

init?(htmlEncodedString: String) {

guard let data = htmlEncodedString.data(using: .utf8) else {
return nil
}

let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue
]

guard let attributedString = try? NSAttributedString(data: data, options: options, documentAttributes: nil) else {
return nil
}

self.init(attributedString.string)

}

}

let encodedString = "The Weeknd <em>‘King Of The Fall’</em>"
let decodedString = String(htmlEncodedString: encodedString)


Related Topics



Leave a reply



Submit