我需要对List<String>
进行排序。它的元素可能包含非 ASCII 字符(想想 é、ž、Æ、...)。有没有办法在 Dart 中做到这一点,同时具有区域设置感知能力?
类似于 localeCompare in Javascript。
一些例子:
捷克语 (cs_CZ)
List<String> czechWords = ['čeština', 'cvrček', 'chleba',];
// expected after calling a localizedSort() or similar method
List<String> czechWordsSorted = ['cvrček', 'čeština', 'chleba',];
Dart 平台库当前没有任何特定于区域设置的字符串排序或比较功能。
如果有人仍然有同样的问题,这是我解决这个问题的方法(在示例中为捷克语)。
理由
这通过替换变音符号字符然后在普通字符串上进行比较来工作。诀窍是扩展规范化和非规范化字符串,但顺序是您想要的。
例如,我想在ú
之前有u
,也就是在ů
之前,所以我可以确保这一点,如果我用所有u
代替ua
,ú
替换ub
,ů
替换uc
。
另一件事是解决ch
;这是通过将h
替换为ha
和ch
代替hb
来完成的(因此每个ch
字符都在h
之后)。
这两种情况都需要一次性完成,因为它们会相互作用。
溶液
const Map<String, String> collTable = {
"a": "aa", "á": "ab", "A": "Aa", "Á": "Ab", "c": "ca", "č": "cb", "C": "Ca",
"Č": "Cb", "d": "da", "ď": "db", "D": "Da", "Ď": "Db", "e": "ea", "é": "eb",
"ě": "ec", "E": "Ea", "É": "Eb", "Ě": "Ec", "i": "ia", "í": "ib", "I": "Ia",
"Í": "Ib", "n": "na", "ň": "nb", "N": "Na", "Ň": "Nb", "o": "oa", "ó": "ob",
"O": "Oa", "Ó": "Ob", "r": "ra", "ř": "rb", "R": "Ra", "Ř": "Rb", "s": "sa",
"š": "sb", "S": "Sa", "Š": "Sb", "t": "ta", "ť": "tb", "T": "Ta", "Ť": "Tb",
"u": "ua", "ú": "ub", "ů": "uc", "U": "Ua", "Ú": "Ub", "Ů": "Uc", "y": "ya",
"ý": "yb", "Y": "Ya", "Ý": "Yb", "z": "za", "ž": "zb", "Z": "Za", "Ž": "Zb",
};
String collKeys = collTable.keys.join("");
final RegExp keysPat = RegExp(r"(cH|ch|CH|Ch|h|H)|([" + collKeys + r"])");
bool isUpperCase(String str){
return str.toUpperCase() == str;
}
String collStr(String str){
return str.replaceAllMapped(keysPat, (match){
assert((match[1] == null) != (match[2] == null));
if(match[1] != null) {
// ch group = either h or ch
String g = match[1]!;
if (g.length == 1) {
// h => ha, H => Ha
return "${g}a";
} else {
assert(g.length == 2);
// need to keep the case of the letters
String subc = isUpperCase(g[0]) ? 'H' : 'h';
// ch => hb, Ch => Hb, CH => Hb, cH => hb
return "${subc}b";
}
}
// diacritics
return collTable[match[2]]!;
});
}
int cmpColl(String a, String b){
return collStr(a).compareTo(collStr(b));
}
用法
然后,您可以像这样使用它:
List<String> czechWords = ['čeština', 'cvrček', 'děda', 'chleba', 'czechia', 'houska', 'imbecilní'];
for(var w in czechWords){
debugPrint("$w -> ${collStr(w)}");
}
czechWords.sort(cmpColl);
debugPrint(czechWords.toString());
哪些打印:
čeština -> cbeasbtaianaaa
cvrček -> cavracbeak
děda -> daecdaaa
chleba -> hbleabaa
czechia -> cazaeahbiaaa
houska -> haoauasakaa
imbecilní -> iambeacaialnaib
[cvrček, czechia, čeština, děda, houska, chleba, imbecilní]
免責聲明
这肯定需要更多的测试:-)
编辑:
比较ch
的代码仍然不完美。目前尚不清楚,大写的顺序应该如何真正,例如Ch
vs.CH
、cH
与ch
等。其中一些可能不是有效的捷克字母......现在,Ch
和CH
都被视为大写ch
,因此顺序是相同的(==结果顺序取决于飞镖sort
是否稳定)。