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
Core Image Filter Cisourceovercompositing Not Appearing as Expected with Alpha Overlay
How to Split a String into a [String] and Not [Substring]
Unwrapping Optional in Swiftui View
Swift Any Difference Between Closures and First-Class Functions
"Raw Value for Enum Case Is Not Unique" for Swift Enum with Float Raw Values
How to Convert 4 Bytes to a Swift Float
Explit Conformance to Codable Removes Memberwise Initializer Generation on Structs
No More 'Private Init' in Swift
Repeating Action Continuously in Swiftui
Constant 'Result' Inferred to Have Type (), Which May Be Unexpected
How to Use Willset and Didset with Getter and Setter
Maccatalyst App: How to Close a Window Without Terminating The App