I'm trying to figure out how to remove the backslash "\" escape character in an array of strings, for words with an apostrophes. Swift automatically adds an escape in strings that have apostrophes, in an array.
For example, suppose I have this:
var tempArray = [String]()
tempArray.append("test")
tempArray.append("one")
tempArray.append("test's")
tempArray.append("right")
print(tempArray[2]) //Prints: test's
print(tempArray) //Prints: ["test", "one", "test\'s", "right"]
As you can see, one of the strings I append into the array is "test's", which has an apostrophe. When I just print this element I get "test's", which is fine. However, when I print the entire array I get "test\'s". I don't want to automatically insert a backslash to "test's"
I would ultimately like to store tempArray as a JSON string in a SQLite database. So If I store this array as is, the backslash "\" will break the JSON.
Why does Swift insert backslashes into an array of strings (It doesn't seem to do so for regular string variables)? And how do I ensure that tempArray prints and stores as a proper JSON string?
I've tried to play with different approaches but have not been able to find a solution. Any help is appreciated. Thank you.
What you need is to encode your array of strings. You can use JSONSerialization method or JSONEncoder. Nowadays you are likely supposed to use Codable protocol only (JSONEncoder/JSONDecoder):
var tempArray = [String]()
tempArray.append("test")
tempArray.append("one")
tempArray.append("test's")
tempArray.append("right")
print(tempArray)
do {
let jsonData = try JSONEncoder().encode(tempArray)
let jsonString = String(data: jsonData, encoding: .utf8) ?? ""
print(jsonString)
} catch {
print(error)
}
This will print:
["test", "one", "test\'s", "right"]
["test","one","test's","right"]
Related
Let's say there's a JSON-string I got from server: "\"3\"" (with quotes, i.e. length == 3 here)
In Android-world, I can do:
gson.fromJson(json, new TypeToken<String>() {}.getType()); - it returns "3" (i.e. length == 1)
In C#-world, can use NewtonSoft.Json:
JsonConvert.DeserializeObject<string>(json, settings) - it returns "3" (i.e. length == 1)
And other way around, I do have string I want to serialize as a JSON.
In Android I'd do gson.toJson("\"3\"") and in C# - JsonConvert.SerializeObject("\"3\"")
The problem with JSONSerialization is that it doesn't treat plain string as a valid JSON: JSONSerialization.isValidJSONObject("\"3\"") == *false*
What would be equivalent in Swift / Obj-C world?
The ugly workaround I've found (except of just adding/removing quotes) so far is to wrap string into 1-item-array to make JSONSerialization happy and then remove "[","]" from resulted JSON-string (and other way around - add "[", "]" before deserialization), but it's a way too disgusting to be the real solution for this problem.
When de-serializing JSON which does not have an array or
dictionary as top-level object you can pass the
.allowFragments option:
let jsonString = "\"3\""
let jsonData = jsonString.data(using: .utf8)!
let json = try! JSONSerialization.jsonObject(with: jsonData, options: .allowFragments)
if let str = json as? String {
print(str) // 3
}
However, there seems to be no way to serialize a plain string to JSON
with the JSONSerialization class from the Foundation library.
Note that according to the JSON specification,
a JSON object is a collection of name/value pairs (dictionary) or
an ordered list of values (array). A single string is not a valid
JSON object.
I am working with a web API that gives me strings like the following:
"Eat pok\u00e9."
Xcode complains that
Expected Hexadecimal code in braces after unicode escape
My understanding is that it should be converted to pok\u{00e9}, but I do not know how to achieve this.
Can anybody point me in the right direction for me develop a way of converting these as there are many in this API?
Bonus:
I also need to remove \n from the strings.
You may want to give us more context regarding what the raw server payload looked like, and show us how you're displaying the string. Some ways of examining strings in the debugger (or if you're looking at raw JSON) will show you escape strings, but if you use the string in the app, you'll see the actual Unicode character.
I wonder if you're just looking at raw JSON.
For example, I passed the JSON, {"foo": "Eat pok\u00e9."} to the following code:
let jsonString = String(data: data, encoding: NSUTF8StringEncoding)!
print(jsonString)
let dictionary = try! NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String: String]
print(dictionary["foo"]!)
And it output:
{"foo": "Eat pok\u00e9."}
Eat poké.
By the way, this standard JSON escape syntax should not be confused with Swift's string literal escape syntax, in which the hex sequence must be wrapped in braces:
print("Eat pok\u{00e9}.")
Swift uses a different escape syntax in their string literals, and it should not be confused with that employed by formats like JSON.
#Rob has an excellent solution for the server passing invalid Swift String literals.
If you need to convert "Eat pok\u00e9.\n" to Eat poké it can be done as follows with Swift 3 regex.
var input = "Eat pok\\u00e9.\n"
// removes newline
input = String(input.characters.map {
$0 == "\n" ? " " : $0
})
// regex helper function for sanity's sake
func regexGroup(for regex: String!, in text: String!) -> String {
do {
let regex = try RegularExpression(pattern: regex, options: [])
let nsString = NSString(string: text)
let results = regex.matches(in: text, options: [], range: NSMakeRange(0, nsString.length))
let group = nsString.substring(with: results[0].range)
return group
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
return ""
}
}
let unicodeHexStr = regexGroup(for:"0\\w*", in: input)
let unicodeHex = Int(unicodeHexStr, radix: 16)!
let char = Character(UnicodeScalar(unicodeHex)!)
let replaced = input.stringByReplacingOccurrencesOfString("\\u"+unicodeHexStr, withString: String(char))
// prints "Eat poké"
print(replaced)
\u{00e9} is a formatting that's specific to Swift String literals. When the code is compiled, this notation is parsed and converted into the actual Unicode Scalar it represents.
What you've received is a String that escapes Unicode scalars in a particlar way. Transform those escaped Unicode Scalars into the Unicode Scalars they represent, see this answer.
I am a newbie to Swift so kindly excuse me if this question sounds too silly.
I am trying to create a JSON object from a dictionary Array output which must have Curly Brackets("{}") after each entity rather than Square brackets ("[]"). My Code is given below.
import UIKit
var locations = Array<Dictionary<String, String>>()
var myLocations = ["pqr","xyz"]
myLocations.forEach {_ in
var dictionary = Dictionary<String, String>()
dictionary["string1"] = "hello"
dictionary["string2"] = "world"
locations.append(dictionary)
}
print(locations)
The output to this is:- [["string2": "world", "string1": "hello"], ["string2": "world", "string1": "hello"]]\n
However I require it as:- [{"string2": "world", "string1": "hello"}, {"string2": "world", "string1": "hello"}]\n
I know one way of doing this is by using filter Arrays but I suspect there could be an easier way to this which I am not able to find after searching through various documentations on Swift. Could you please help me with this. Thanks in advance.
The output is
[["string2": "world", "string1": "hello"], ["string2": "world", "string1": "hello"]]
because this is a Swift array of Swift dictionaries.
To convert this object to JSON, do not parse and replace the characters yourself, use NSJSONSerialization instead:
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(locations, options: [])
if let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding) {
print(jsonString)
}
} catch {
print(error)
}
Prints:
[{"string2":"world","string1":"hello"},{"string2":"world","string1":"hello"}]
We use dataWithJSONObject to convert your Swift object to JSON data, then we use String(data:, encoding:) to convert this JSON data to a JSON string.
This might be a very stupid question but I can't seem to find an answer.
I have this piece of code which converts an input of numbers into doubles :
var array: [Double]! = []
data = try String(contentsOfFile: localFilePath as String,
encoding: NSASCIIStringEncoding)
let myStrings = data.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
var trial = myStrings[0].componentsSeparatedByString(",").flatMap{Double($0.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()))}
array.append(trial)
So for example if my file has these numbers 1.2,3.4,5.6 then the output will be [1.2,3.4,5.6] and so on.
I get the above error when I try to append my array, what is the right way of casting this? Thank you.
What you are looking for is appendContentsOf, not append.
flatMap returns a [Double], and you want to append the contents of that array to array.
Merely change
array.append(trial)
to:
array.appendContentsOf(trial)
I am using the Maps API and when searching for some addresses in foreign countries, the address comes back with Unicode characters embedded like this:
"Place du Panth\U00e9on",
"75005 Paris"
The unicode character in this instance is \U00e9 which is é
The trouble I have having is that SwiftyJSON pukes if I have saved this data in a JSON file and try to read it back. SwiftyJSON does not like the back slash character '\' The JSON is valid and even if I could read it, it is still not good as I would rather have é displayed properly as well as all other Unicode characters.
Does anyone have any ideas on how to convert all unicode characters to UTF8 encoding of that character in Swift?
Should I just write a function that searches for all of the Unicode characters and then convert them?
Unless someone has a better idea, I just wrote this function that is doing the trick for me now.
func convertFromUnicode(var myString:String) -> String {
let convertDict:[String:String] = ["\\U00c0":"À", "\\U00c1" :"Á","\\U00c2":"Â","\\U00c3":"Ã","\\U00c4":"Ä","\\U00c5":"Å","\\U00c6":"Æ","\\U00c7":"Ç","\\U00c8":"È","\\U00c9":"É","\\U00ca":"Ê","\\U00cb":"Ë","\\U00cc":"Ì","\\U00cd":"Í","\\U00ce":"Î","\\U00cf":"Ï","\\U00d1":"Ñ","\\U00d2":"Ò","\\U00d3":"Ó","\\U00d4":"Ô","\\U00d5":"Õ","\\U00d6":"Ö","\\U00d8":"Ø","\\U00d9":"Ù","\\U00da":"Ú","\\U00db":"Û","\\U00dc":"Ü","\\U00dd":"Ý","\\U00df":"ß","\\U00e0":"à","\\U00e1":"á","\\U00e2":"â","\\U00e3":"ã","\\U00e4":"ä","\\U00e5":"å","\\U00e6":"æ","\\U00e7":"ç","\\U00e8":"è","\\U00e9":"é","\\U00ea":"ê","\\U00eb":"ë","\\U00ec":"ì","\\U00ed":"í","\\U00ee":"î","\\U00ef":"ï","\\U00f0":"ð","\\U00f1":"ñ","\\U00f2":"ò","\\U00f3":"ó","\\U00f4":"ô","\\U00f5":"õ","\\U00f6":"ö","\\U00f8":"ø","\\U00f9":"ù","\\U00fa":"ú","\\U00fb":"û","\\U00fc":"ü","\\U00fd":"ý","\\U00ff":"ÿ"]
for (key,value) in convertDict {
myString = myString.stringByReplacingOccurrencesOfString(key, withString: value)
}
return myString
}
Instead of hardcoding all the characters I would decode it with an extension like:
extension String {
var decoded : String {
let data = self.data(using: .utf8)
let message = String(data: data!, encoding: .nonLossyASCII) ?? ""
return message
}
}
and then you could use it like this:
let myString = "Place du Panth\\U00e9on"
print(myString.decoded)
Which would print Place du Panthéon