How to convert special characters in dictionary to unicode in swift - ios

//temporary dictionary
let tempDict = ["ttTasks":"€ is euro symbol"]
//conversion should replace € symbol with \u20ac
so final dictionary would be
finalDict = ["ttTasks":"\u20ac is euro symbol"]
NOTE: please do not suggest me replaceOccurencesOfString as i need to do this for every special character.

Something like this maybe:
for key in tempDict.keys {
let data = tempDict[key]?.data(using: String.Encoding.nonLossyASCII)
tempDict[key] = String(data: data!, encoding: String.Encoding.utf8)
}

Related

Swift error when creating a String from a range of a special character

I'm having a problem when I want to create string from a index of string that contains a special character. I'll post you a playground example.
var str = """
circular para poder realizar sus tareas laborales correspondientes a las actividades de comercialización de alimentos
"""
let regex = try? NSRegularExpression(pattern: ".", options: .caseInsensitive)
let results = regex?.matches(in: str, options: .withoutAnchoringBounds, range: NSRange(0..<str.count - 1))
results?.forEach { result in
let newStr = String(str[Range(result.range, in: str)!])
print(newStr)
}
Now I get an error when the range of the character "ó" wants to form a string. How can I solve this?
Thanks
There are two problems. One is that the NSRange must be created from the count of UTF-16 code units int the string (because that is what NSString uses), compare Swift extract regex matches. So that should be NSRange(0..<str.utf16.count) or NSRange(str.startIndex..., in: str).
The other problem is that the string uses decomposed Unicode characters. Here is a simplified demonstration:
let str = "ó"
print(Array(str.utf16))
let regex = try? NSRegularExpression(pattern: ".", options: .caseInsensitive)
let results = regex?.matches(in: str, range: NSRange(str.startIndex..., in: str))
results?.forEach { result in
print(result.range, Range(result.range, in: str))
}
// Output:
// [111, 769]
// {0, 1} nil
// {1, 1} nil
NSRegularExpression is an “old” Foundation method and works on an NSString. Here that NSString has two UTF-16 characters, and both are matched by the "." pattern.
The problem is that the returned NSRanges do not correspond to Swift String ranges, and therefore Range(result.range, in: str) returns nil.
A possible solutions is to normalize the string to use only composite Unicode characters:
let str = "ó".precomposedStringWithCanonicalMapping
Now the string has only a single Unicode character, and only a single NSRange is returned. The above test program produces the output
// [243]
// {0, 1} Optional(Range(Swift.String.Index(...)))

How to split uncode string into characters

I have strings like
"\U0aac\U0ab9\U0ac1\U0ab5\U0a9a\U0aa8",
"\U0a97\U0ac1\U0ab8\U0acd\U0ab8\U0acb",
"\U0aa6\U0abe\U0ab5\U0acb",
"\U0a96\U0a82\U0aa1"
But I want to split this strings by unicode character
I dont know hot to do. I know components seprated by function but it's no use here.
\nAny help would be apperiaciated
If the strings you're getting really contain \U characters, you need to parse them manually and extract the unicode scalar values. Something like this:
let strings = [
"\\U0aac\\U0ab9\\U0ac1\\U0ab5\\U0a9a\\U0aa8",
"\\U0a97\\U0ac1\\U0ab8\\U0acd\\U0ab8\\U0acb",
"\\U0aa6\\U0abe\\U0ab5\\U0acb",
"\\U0a96\\U0a82\\U0aa1"
]
for str in strings {
let chars = str.components(separatedBy: "\\U")
var string = ""
for ch in chars {
if let val = Int(ch, radix: 16), let uni = Unicode.Scalar(val) {
string.unicodeScalars.append(uni)
}
}
print(string)
}
You can map your array, split its elements at non hexa digit values, compact map them into UInt32 values, initializate unicode scalars with them and map the resulting elements of your array into a UnicodeScalarView and init a new string with it:
let arr = [
#"\U0aac\U0ab9\U0ac1\U0ab5\U0a9a\U0aa8"#,
#"\U0a97\U0ac1\U0ab8\U0acd\U0ab8\U0acb"#,
#"\U0aa6\U0abe\U0ab5\U0acb"#,
#"\U0a96\U0a82\U0aa1"#]
let strings = arr.map {
$0.split { !$0.isHexDigit }
.compactMap { UInt32($0, radix: 16) }
.compactMap(Unicode.Scalar.init)
}.map { String(String.UnicodeScalarView($0)) }
print(strings)
This will print
["બહુવચન", "ગુસ્સો", "દાવો", "ખંડ"]
So, the string that comes back already has the "\" because in order to use components you'd need to have an additional escaping "\" so that you'd be able to do:
var listofCodes = ["\\U0aac\\U0ab9\\U0ac1\\U0ab5\\U0a9a\\U0aa8", "\\U0aac\\U0ab9\\U0ac1\\U0ab5\\U0a9a\\U0aa8"]
var unicodeArray :[String] = []
listofCodes.forEach { string in
unicodeArray
.append(contentsOf: string.components(separatedBy: "\\"))
unicodeArray.removeAll(where: {value in value == ""})
}
print(unicodeArray)
I will revise this answer once you specify how you are obtaining these strings, as is I get a non-valid string error from the start.

Swift Array to String

There is an array like:
let datas =
[["#A1CCE4","", "+0.0%", "+0.0%"],
["#4C3C2F","G", "+1.0%", "+0.2%"],
["#4C3C2F","G", "+3.1%", "+0.6%"],
["#C07155","S", "+0.3%", "+0.1%"],
["#C07155","G", "+2.0%", "+0.4%"],
["#C07155","P", "+1.8%", "+0.3%"],
["#AEB0B3","R", "+2.0%", "+2.0%"]]
How to convert it to string like:
"""let data = [["#A1CCE4", "", "+0.0%", "+0.0%"], ["#4C3C2F", "G", "+1.0%", "+0.2%"], ["#4C3C2F", "G", "+3.1%", "+0.6%"], ["#C07155", "S", "+0.3%", "+0.1%"], ["#C07155", "G", "+2.0%", "+0.4%"], ["#C07155", "P", "+1.8%", "+0.3%"], ["#AEB0B3", "R", "+2.0%", "+2.0%"]]"""
(with "let data = " or not is fine)
EDIT:
"\(datas)" should be the answer.
or
"\(String(describing: datas))"
or
datas.description
Why do I ask this question?
The array actually from the plist, and the number values are from different places.
The number values need to be load in the js code in WKWebView. And acutually the js code is just string.
In my js code I have actually the same code datas variable code.
You actually want to create a JSON string, it's pretty easy with JSONEncoder because [String] conforms to Encodable by default.
let datas =
[["#A1CCE4","", "+0.0%", "+0.0%"],
["#4C3C2F","G", "+1.0%", "+0.2%"],
["#4C3C2F","G", "+3.1%", "+0.6%"],
["#C07155","S", "+0.3%", "+0.1%"],
["#C07155","G", "+2.0%", "+0.4%"],
["#C07155","P", "+1.8%", "+0.3%"],
["#AEB0B3","R", "+2.0%", "+2.0%"]]
do {
let jsonData = try JSONEncoder().encode(datas)
let result = String(data: jsonData, encoding: .utf8)!
print(result)
} catch { print(error) }
It's more reliable than just calling .description on the array.
And only an array literal is directly interchangeable with JSON, a dictionary is not.
If you really need the let datas = prefix just concatenate the strings
let resultWithPrefix = "let datas = " + result
Given your datas array, you can achieve your goal this way:
let datas =
[["#A1CCE4","", "+0.0%", "+0.0%"],
["#4C3C2F","G", "+1.0%", "+0.2%"],
["#4C3C2F","G", "+3.1%", "+0.6%"],
["#C07155","S", "+0.3%", "+0.1%"],
["#C07155","G", "+2.0%", "+0.4%"],
["#C07155","P", "+1.8%", "+0.3%"],
["#AEB0B3","R", "+2.0%", "+2.0%"]]
var str = " let datas = ["
for data in datas{
str += "\(data)"
}
str += "]"
EDIT:
You can use this code, with a loop for each String array in your data, to get a string with comma
var str = " let datas = ["
for data in datas{
str += "["
for s in data{
str += " \" \(s) \" , "
}
str += "],"
}
str += "]"
Another good solution is to use JSONEncoder, as suggested in other answer, I just report it here to complete
let datas = [...]
var myString = "let datas ="
do{
let datasToJson = JSONEncoder().encode(datas)
myString += String(data: datasToJson, encoding: .utf8)!
}catch{
print(error)
}
How about something like this:
let stringStart = "let datas = "
let stringDatas = String(datas)
let finalString = stringStart + stringDatas
More answers here

How Fix Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 52."

How to Convert this one. "{\n ID = \"d9a7c7bf-781d-47b3-bb4e-e1022ec4ce1b\";\n Name = Headquarters;\n}"; To this format {
"ID": "d9a7c7bf-781d-47b3-bb4e-e1022ec4ce1b",
"Name": "Headquarters"
}
if let jsonString = text as? String {
let objectData = jsonString.data(using: String.Encoding.utf8)
do {
let json = try JSONSerialization.jsonObject(with: objectData!, options: .allowFragments) as! [String:Any] //try JSONSerialization.jsonObject(with: objectData!, options: JSONSerialization.ReadingOptions.mutableContainers)
print(String(describing: json))
return json
} catch {
// Handle error
print(error)
}
}
Blockquote
First of all and already mentioned the string format is clearly not JSON.
It's the string format which is returned when calling the description property of a Foundation collection type (NSArray / NSDictionary).
For example a print statement calls description and this format appears also in output of Terminal.app.
However there is a solution: This string format is called openStep (an OpenStep / NeXt legacy format) and is available in PropertyListSerialization
This code reads the format:
let string = "{\n ID = \"d9a7c7bf-781d-47b3-bb4e-e1022ec4ce1b\";\n Name = Headquarters;\n}"
let data = Data(string.utf8)
do {
let dictionary = try PropertyListSerialization.propertyList(from: data, format: nil)
print(dictionary)
} catch { print(error) }
Note:
I'm pretty sure that the original data format is not openStep and somewhere you created the string unnecessarily with the String(describing initializer like in the question.
your json format is incorrect. If you try it with jsonformatter it will throw this error:
so first you need to replace ; with ,. The second is that Strings should be wrapped in double quotes, replace Name = Headquarters with Name = "Headquarters".
This is the right form
{\n ID = \"d9a7c7bf-781d-47b3-bb4e-e1022ec4ce1b\",
\n Name = "Headquarters"\n}

Create a JSON String in Swift

I send the text from a TextView to my Backend. To include linebreaks, i try to serialize the textView.text to JSON.
let jsonObject: NSMutableDictionary = NSMutableDictionary()
jsonObject.setValue(textView.text, forKey: "text")
let jsonData: NSData
do {
jsonData = try JSONSerialization.data(withJSONObject: jsonObject, options: JSONSerialization.WritingOptions()) as NSData
let jsonString = NSString(data: jsonData as Data, encoding: String.Encoding.utf8.rawValue) as! String
print(jsonString)
} catch _ {
print ("JSON Failure")
}
}
But since this is a Dictionary, the resulting text looks like this:
{"text":"test\nstack\n\noverflow"}
i actually just need: test\nstack\n\noverflow
Is there a pretty way to transform a multiline String in swift to have these "\n" for linebreaks without any extra characters?
Edit:
I expect to type into my textView something like this:
and as a result get the string "hello\n\n"
The source looks like this:
let text = textView.text
let components = text?.components(separatedBy: CharacterSet.newlines).filter({!$0.isEmpty})
let textWithLineFeeds = components?.joined(separator:"\n")
print(textWithLineFeeds!)
print(textView.text)
the first print gives:
test
hello
linebreak above
the second print statement:
test
hello
linebreak above
i wish i could see:
test\nhello\n\nlinebreak above
To convert text with arbitrary new line characters (CR, LF, CRLF etc.) to distinct - only LF - line breaks use:
let text = "test\r\nstack\n\noverflow\rfoo"
let components = text.components(separatedBy: CharacterSet.newlines).filter({!$0.isEmpty})
let textWithLineFeeds = components.joined(separator:"\n")
If the server accepts only CR, change \n to \r.

Resources