FMDB:SQLite 语句 ORDER BY 错误地命令变音符号

Cla*_*olf 3 sqlite fmdb ios swift xcode6

我对 iOS 开发很陌生,我有很多东西要学习。它就像一座巨大的山,但多亏了你的帮助,我才找到了位置;)

我已经启动了一个 Xcode 项目(Xcode 版本 6.1.1、Swift、iOS)并包含 FMDB 来运行 SQLite 查询。查询执行得很好,但是在以下语句中:

var resultSet: FMResultSet! = sharedInstance.database!.executeQuery("SELECT * FROM spesenValues ORDER BY country ASC", withArgumentsInArray: nil)
Run Code Online (Sandbox Code Playgroud)

从我的角度来看,字母顺序是错误的,但我似乎不知道如何解决它。标准的 AZ 字符被排序到我期望的位置,但是任何包含变音符号的字符,例如 ÄÖÜ 都被排序到列表的最底部。

所以我期望的是:

Österreich ... Zypern

但我得到的是

Zypern ... Österreich

SQLite Order By 在末尾放置变音符号和特殊字符,我了解到这归结为“iOS 上的 SQLite 未启用 ICU”这一事实。

有没有一种简单的方法来配置 FMDB 来帮助我“正确”排序。提前谢谢你,如果这变成一个超级愚蠢的问题,我很抱歉

Rob*_*Rob 5

您可以定义自己的 SQLite 函数,用于CFStringTransform删除重音符号。使用 FMDB 2.7:

db.makeFunctionNamed("unaccented", arguments: 1) { context, argc, argv in
    guard db.valueType(argv[0]) == .text || db.valueType(argv[0]) == .null else {
        db.resultError("Expected string parameter", context: context)
        return
    }

    if let string = db.valueString(argv[0])?.folding(options: .diacriticInsensitive, locale: nil) {
        db.resultString(string, context: context)
    } else {
        db.resultNull(context: context)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以unaccented在你的 SQL 中使用这个新函数:

do {
    try db.executeQuery("SELECT * FROM spesenValues ORDER BY unaccented(country) ASC" values: nil) 

    while rs.next() {
        // do what you want with results
    }

    rs.close()
} else {
    NSLog("executeQuery error: %@", db.lastErrorMessage())
}
Run Code Online (Sandbox Code Playgroud)

You suggest that you want to replace "ä", "ö", and "ü" with "ae", "oe", and "ue", respectively. This is generally only done with proper names and geographical names (see Wikipedia's entry for German orthography), but if you wanted to do that, have your custom function (which I've renamed "sortstring") replace these values as appropriate:

db.makeFunctionNamed("sortstring", arguments: 1) { context, argc, argv in
    guard argc == 1 && (db.valueType(argv[0]) == .text || db.valueType(argv[0]) == .null) else {
        db.resultError("Expected string parameter", context: context)
        return
    }

    let replacements = ["ä": "ae", "ö": "oe", "ü": "ue", "ß": "ss"]

    var string = db.valueString(argv[0])!.lowercased()

    for (searchString, replacement) in replacements {
        string = string.replacingOccurrences(of: searchString, with: replacement)
    }

    db.resultString(string.folding(options: .diacriticInsensitive, locale: nil), context: context)
}
Run Code Online (Sandbox Code Playgroud)

By the way, since you're using this just for sorting, you probably want to convert this to lowercase, too, so that the upper case values are not separated from the lower case values.

But the idea is the same, define whatever function you want for sorting, and then you can use FMDB's makeFunctionNamed to make it available in SQLite.