【问题标题】:trying to parse a Localizable.string file for a small project in swift on MacOS试图在 MacOS 上快速解析一个小项目的 Localizable.string 文件
【发布时间】:2017-02-03 23:00:45
【问题描述】:

我正在尝试在 MacOS 上快速解析一个小型项目的 Localizable.string 文件。 我只想检索文件中的所有键和值以将它们排序到字典中。

为此,我在NSRegularExpression cocoa 类中使用了正则表达式。

这是这些文件的样子:

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

这是我的代码,它应该从加载到 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 []
    }
}

使用提供的 Localizable 示例运行此代码时,输​​出如下:

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

听起来比赛在第一次出现" 后并没有停止。当我在 regex101.com 上尝试相同的表达式 \"(.*)\"[ ]*=[ ]*\"(.*)\"; 时,输出是正确的。我做错了什么?

【问题讨论】:

标签: regex swift string macos nsregularexpression


【解决方案1】:

对于任何感兴趣的人,我都可以使用原始功能。我需要它用于 NSDictionary(contentsOf: URL) 不起作用的小型命令行脚本。

func matches(for regex: String, in text: String) -> [String] {
    do {
        let regex = try NSRegularExpression(pattern: regex)
        let nsString = text as NSString
        guard let result = regex.firstMatch(in: text, options: [], range: NSRange(location: 0, length: nsString.length)) else {
            return [] // pattern does not match the string
        }
        return (1 ..< result.numberOfRanges).map {
            nsString.substring(with: result.range(at: $0))
        }
    } catch let error as NSError {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

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

    for line in text.components(separatedBy: "\n") {
        let match = matches(for: exp, in: line)
        if match.count == 2 {
            dict.append((key: match[0], text: match[1]))
        }
    }
    return dict
}

使用类似这样的方式调用它。

let text = try! String(contentsOf: url, encoding: .utf8)

let stringDict = getParsedText(text: text)

【讨论】:

    【解决方案2】:

    你的函数(来自Swift extract regex matches?)匹配整个模式 只要。如果您对特定的捕获组感兴趣,那么 您必须使用rangeAt() 访问它们,例如 Convert a JavaScript Regex to a Swift Regex(尚未针对 Swift 3 进行更新)。

    但是有一个更简单的解决方案,因为 .strings 文件实际上使用了一种可能的属性列表格式,并且 可以直接读入字典。示例:

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

    输出:

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

    【讨论】:

    • 感谢 Martin,它已修复。我会发布我的代码,以防它帮助其他人。不过我不知道 NSDictionary 解决方案,这太棒了!
    • 哇,这样的作品真的很棒。可悲的是,还没有找到一种方法来保存context(以上行的cmets):/
    • @Jakub:是的,将文件作为属性列表读取时会忽略 cmets。我不知道有什么解决方法(除了“手动”解析文件)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-27
    • 2019-08-23
    • 2018-12-09
    • 1970-01-01
    • 1970-01-01
    • 2022-08-22
    相关资源
    最近更新 更多