Edgar Edgar - 1 year ago 51
Swift Question

trying to parse a Localizable.string file for a small project in swift on MacOS

I'm trying to parse a Localizable.string file for a small project in swift on MacOS.
I just want to retrieve all the keys and values inside a file to sort them into a dictionary.

To do so I used regex with the

cocoa class.

Here is what those file look like :

"key 1" = "Value 1";
"key 2" = "Value 2";
"key 3" = "Value 3";

Here is my code that is supposed to get the keys and values from the file loaded into a

static func getDictionaryFormText(text: String) -> [String: String] {
var dict: [String : String] = [:]
let exp = "\"(.*)\"[ ]*=[ ]*\"(.*)\";"

for line in text.components(separatedBy: "\n") {
let match = self.matches(for: exp, in: line)
// Following line can be uncommented when working
//dict[match[0]] = match[1]
print("(\(match.count)) matches = \(match)")
return dict

static 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 as NSError {
print("invalid regex: \(error.localizedDescription)")
return []

When running this code with the provided Localizable example here is the output :

(1) matches = ["\"key 1\" = \"Value 1\";"]
(1) matches = ["\"key 2\" = \"Value 2\";"]
(1) matches = ["\"key 3\" = \"Value 3\";"]

It sounds like the match doesn't stop after the first
occurence. When i try the same expression
\"(.*)\"[ ]*=[ ]*\"(.*)\";
on regex101.com the output is correct though. What am i doing wrong ?

Answer Source

Your function (from Swift extract regex matches ?) matches the entire pattern only. If you are interested in the particular capture groups then you have to access them with rangeAt() as for example in Convert a JavaScript Regex to a Swift Regex (not yet updated for Swift 3).

However there is a much simpler solution, because .strings files actually use one possible format of property lists, and can be directly read into a dictionary. Example:

if let url = Bundle.main.url(forResource: "Localizable", withExtension: "strings"),
    let stringsDict = NSDictionary(contentsOf: url) as? [String: String] {


["key 1": "Value 1", "key 2": "Value 2", "key 3": "Value 3"]