0

I'm looking for a way to convert this string into array using Swift 3.0

let arrayString: String = "[\"One\", \"Two\", \"Three\", \"Four\"]"

// Should be converted into:

let array: [String] = [
    "One",
    "Two",
    "Three",
    "Four"
]

If I separate it into token using , as the separator, it will include [ and ] so it won't work. How to convert this properly?

Note:

The question is different from: Simple and clean way to convert JSON string to Object in Swift

I'm not trying to convert an JSON Object that has multiple keys in it.

Edward Anthony
  • 3,354
  • 3
  • 25
  • 40
  • 1
    Same question with Swift 2 solution here: [Swift Convert A String-As-An-Array, To An Array Of Strings](https://stackoverflow.com/questions/36731802/swift-convert-a-string-as-an-array-to-an-array-of-strings) – Martin R Aug 16 '17 at 05:55

3 Answers3

7

it's a JSON String, you have to convert it in normal string array by using JSONSerialization.

Swift 3.0

func convertToArray(str: String) -> [String]? {

    let data = str.data(using: .utf8)

    do {
        return try JSONSerialization.jsonObject(with: data!, options: []) as? [String]
    } catch {
        print(error.localizedDescription)
    }

   return nil

 }

let aString: String = "[\"One\", \"Two\", \"Three\", \"Four\"]"

let arrayString = convertToArray(str: aString)

print(arrayString) // ["One", "Two", "Three", "Four"]
Ujesh
  • 1,698
  • 2
  • 23
  • 35
1

There can be a bunch of ways to achieve what you want, but I think one of the most easy is the following:

let newArray = arrayString
 .replacingOccurrences(of: "[", with: "")
 .replacingOccurrences(of: "]", with: "")
 .replacingOccurrences(of: "\"", with: "")
 .components(separatedBy: ",")

And the output should be:

["One", " Two", " Three", " Four"]

EDIT: As @MartinR suggested the previous answer doesn't work if any of the strings contains a comma or a square bracket. So to fix that you can remove the square brackets supposing that always are there of course at the beginning and in the end and then use regex to match everything inside the \"()\" like in the following code:

Let's use the following function to match regex:

func matches(for regex: String, in text: String) -> [String] {
   do {
       let regex = try NSRegularExpression(pattern: regex)
       let nsString = text as NSString
       let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
       return results.map { nsString.substring(with: $0.range)}
   } catch let error {
       print("invalid regex: \(error.localizedDescription)")
       return []
   }
}

For more reference, you can see the @MartinR answer here

With that function we can use the following code to achieve what we want:

let str = "[\"One[\",\"T,w,o,\",\"Thr,ee,,,\",\"Fo,ur,,,\"]"

// remove the square brackets from the array
let start = str.index(str.startIndex, offsetBy: 1)
let end = str.index(str.endIndex, offsetBy: -1)
let range = start..<end
let newString = str.substring(with: range)

// match the regex 
let matched = matches(for: "(?<=\")(.*?)(?=\")", in: newString) // ["One[", ",", "T,w,o,", ",", "Thr,ee,,,", ",", "Fo,ur,,,"] 

But the previous matched include the "," in the array so let's fix that with the following code:

let stringArray = matched.enumerated()
       .filter { $0.offset % 2 == 0 }
       .map { $0.element }

With the following output:

["One[", "T,w,o,", "Thr,ee,,,", "Fo,ur,,,"]

I hope this helps you.

Victor Sigler
  • 23,243
  • 14
  • 88
  • 105
  • 1
    It works but we can't check if the value resembles an array, for example if the user put `[[[1,]` or some other string that doesn't have array format, it won't return optional value. – Edward Anthony Aug 16 '17 at 05:27
  • 1
    Yes, you're right but your question was not about that isn't? My answer solves your question, you never said anything about that. Again the bunch of ways of solve that is big, for that you can regular expressions to validate the input and then mapping it. – Victor Sigler Aug 16 '17 at 05:33
  • 1
    This is fragile. It does not work correctly if any of the strings contains a comma or a square bracket. – Martin R Aug 16 '17 at 05:47
  • @MartinR You're completely right, thanks for the observation – Victor Sigler Aug 16 '17 at 06:28
1

Here is custom code to convert into array:

var arrayString: String = "[\"One\", \"Two\", \"Three\", \"Four\"]"
arrayString = arrayString.replacingOccurrences(of: "[", with: "")
arrayString = arrayString.replacingOccurrences(of: "]", with: "")
arrayString = arrayString.replacingOccurrences(of: " ", with: "")
arrayString = arrayString.replacingOccurrences(of: "\"", with: "")
print("\(arrayString)")
var arr: [Any] = arrayString.components(separatedBy: ",")
print("\(arr)")

If you get above string from API and its JSON then use below:

extension String {
    func toJSON(): Any? {
        guard let data = self.data(using: .utf8, allowLossyConversion: false) else { return nil }
        return try? JSONSerialization.jsonObject(with: data, options: .mutableContainers)
    }
}
Nirmalsinh Rathod
  • 5,079
  • 4
  • 26
  • 56