Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 NSRegularExpression 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 String :

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 ?

like image 603
Edgar Avatar asked Jan 06 '23 07:01

Edgar


1 Answers

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] {
    print(stringsDict)
}

Output:

["key 1": "Value 1", "key 2": "Value 2", "key 3": "Value 3"]
like image 185
Martin R Avatar answered Jan 13 '23 10:01

Martin R