Я пытаюсь сортировать массив/списки/независимо от данных, основанных на строковых значениях unicode в них, которые содержат неанглийские символы, я хочу, чтобы они отсортировались правильно в алфавитном порядке.
Я написал много кода (D2010, win XP), который, как я думал, был достаточно прочным для будущей интернационализации, но это не так. Его все использует тип unicodestring (string), который до сих пор я просто помещал английские символы в строки unicode.
Кажется, мне приходится иметь дело с серьезной ошибкой unicode. Я поговорил с моим немецким другом и попробовал некоторые немецкие ß, (ß "ss" и должен появиться после S и до T в алфавите), и ö и т.д. (Обратите внимание на умлаут), и ни один из моих алгоритмов сортировки больше не работает. Результаты очень смешаны. Garbage.
С тех пор я много читаю и узнал много неприятных вещей в отношении сортировки юникода. Все выглядит мрачно, гораздо мрачнее, чем я ожидал, я серьезно испортил это. Надеюсь, что у меня что-то не хватает, и на самом деле все не так мрачно, как сейчас. Я не занимался просмотром вызовов windows api (RtlCompareUnicodeString) без успеха (ошибки защиты), я не мог заставить его работать. Проблема с вызовами API, которые я узнал, заключается в том, что они меняются на разных новых платформах Windows, а также с delphi, идущими на Cross Plat в ближайшее время, с linux позже, мое приложение - это клиентский сервер, поэтому мне нужно беспокоиться об этом, но tbh с ситуацией это (плохо), я был бы признателен за любой поступательный прогресс, т.е. выиграть api specific.
Использует функцию win api RtlCompareUnicodeString для очевидного решения? Если это так, я должен попробовать еще раз с этим, но tbh. Я был ошеломлен всеми проблемами, связанными с сортировкой юникодов, и я не совсем понимаю, что я должен делать, чтобы сравнивать эти строки таким образом в любом случае.
Я узнал о проекте open source IBM ICU С++, для него есть оболочка delphi, хотя для более старой версии ICU. Это очень комплексное решение, которое является независимым от платформы. Конечно, я не могу смотреть на создание оболочки delphi для этого (или обновления существующего), чтобы получить хорошее решение для сортировки unicode?
Я был бы очень рад услышать совет на двух уровнях: -
A) Нестандартное решение для Windows, я был бы рад тому, что на данный момент забыл о последствиях клиентского сервера! B) Более портативное решение, которое невосприимчиво к различным вариациям XP/vista/win7 функций api для юникода, поэтому я хорошо поддерживаю поддержку Mac OS XE2 и поддержку будущего Linux, не говоря уже о осложнениях на клиентском сервере.
Btw Я действительно не хочу делать решения "make-do", сканировать строки перед сравнением и заменять некоторые сложные символы и т.д., о которых я читал. Я дал немецкий экзамен выше, это просто пример, я хочу, чтобы он работал на всех (или, по крайней мере, на большинстве, на дальнем востоке, русском) языках, я не хочу делать обходные пути для определенного языка или двух. Мне также не нужны какие-либо рекомендации по алгоритмам сортировки, они в порядке, это просто бит сравнения строк, который был неправильным.
Надеюсь, что я упускаю/делаю что-то глупое, все это выглядит головной болью.
Спасибо.
EDIT, Руди, вот как я пытался вызвать RtlCompareUnicodeString. Извините за задержку, с которой у меня было ужасное время.
program Project26
{$APPTYPE CONSOLE}
uses
SysUtils;
var
a,b:ansistring;
k,l:string;
x,y:widestring;
r:integer;
procedure RtlInitUnicodeString(
DestinationString:pstring;
SourceString:pwidechar) stdcall; external 'NTDLL';
function RtlCompareUnicodeString(
String1:pstring;
String2:pstring;
CaseInSensitive:boolean
):integer stdcall; external 'NTDLL';
begin
x:='wef';
y:='fsd';
RtlInitUnicodeString(@k, pwidechar(x));
RtlInitUnicodeString(@l, pwidechar(y));
r:=RtlCompareUnicodeString(@k,@l,false);
writeln(r);
readln;
end.
Я понимаю, что это скорее всего неправильно, я не привык к вызову api unctions напрямую, это мое лучшее предположение.
О вашей функции apiStringCompareEx. Это выглядело очень хорошо, но доступно только для Vista +, я использую XP. StringCompare находится на XP, но это не Unicode!
Чтобы вернуться к основной задаче, нужно сравнить две строки и сделать это на основе порядка сортировки символов, указанного в текущем локали Windows.
Может ли кто-нибудь сказать наверняка, должен ли это делать ansicomparetext или нет? Это не работает для меня, но другие сказали, что это нужно, и другие вещи, которые я прочитал, предлагают это.
Это то, что я получаю с 31 тестовой строкой при использовании AnsiCompareText, когда в German Locale (пробел ограничен - строки не содержат пробелов): -
- arß Asß asß aßs no nö ö ön oo öö oöo öoö öp pöss SS ßaß ßbß sß Sßa Sßb ßß ssss SSSS ßßß ssßß SSßß ßz ßzß z zzz
ИЗМЕНИТЬ 2.
Я все еще хочу услышать, должен ли я ожидать, что AnsiCompareText будет работать с использованием информации о локали, как сказал lkessler, и lkessler также опубликовал об этих предметах раньше и, кажется, уже прошел это раньше.
Однако, следуя рекомендациям Rudy, я также проверял CompareStringW, который разделяет ту же документацию с CompareString, поэтому НЕ НЕ -никод, как я уже говорил ранее.
Даже если AnsiCompareText не будет работать, хотя я думаю, что он должен работать, функция win32api CompareStringW действительно должна работать. Теперь я определил свою функцию API, и я могу назвать ее, и я получаю результат, и никакой ошибки... но я получаю тот же результат каждый раз, независимо от входных строк! Он возвращает 1 каждый раз, что означает меньше. Здесь мой код
var
k,l:string;
function CompareStringW(
Locale:integer;
dwCmpFlags:longword;
lpString1:pstring;
cchCount1:integer;
lpString2:pstring;
cchCount2:integer
):integer stdcall; external 'Kernel32.dll';
begin;
k:='zzz';
l:='xxx';
writeln(length(k));
r:=comparestringw(LOCALE_USER_DEFAULT,0,@k,3,@l,3);
writeln(r); // result is 1=less than, 2=equal, 3=greater than
readln;
end;
Я чувствую, что теперь я получаю кое-что после боли. Был бы рад узнать об AnsiCompareText и о том, что я делаю неправильно с вышеупомянутым вызовом CompareStringW api. Спасибо.
ИЗМЕНИТЬ 3
Во-первых, я исправил api-вызов для CompareStringW сам, я проходил в @mystring, когда мне нужно было PString (mystring). Теперь все работает правильно.
r:=comparestringw(LOCALE_USER_DEFAULT,0,pstring(k),-1,pstring(l),-1);
Теперь вы можете представить себе мое беспокойство, когда я все еще получаю тот же результат сортировки, что и в начале...
- arß asß aßs Asß no nö ö ön oo öö oöo öoö öp pöss SS ßaß ßbß sß Sßa Sßb ßß ssss SSSS ßßß ssßß SSßß ßz ßzß z zzz
Вы также можете представить себе мое ЧРЕЗВЫЧАЙНОЕ смятение, не говоря уже о одновременной радости, когда я понял, что порядок сортировки ПРАВИЛЬНО, и ЭТО ПРАВИЛЬНО ПРАВИЛЬНО НАХОДИТСЯ В ПОЛУЧЕНИИ! Это заставило sme больно сказать это, но в первую очередь никогда не было никаких проблем - все это связано с отсутствием немецкого знания. Я полагал, что это было неправильно, так как вы можете видеть, что начало строки начинается с S, а затем они начинаются с ß, затем с снова и обратно до ß и так далее. Ну, я не могу говорить по-немецки, но я все еще мог ясно видеть, что они не были отсортированы правильно - мой немецкий друг сказал мне, что ß приходит после S и до T... Я был НЕПРАВИЛЬНО! Что происходит, так это то, что строковые функции (как AnsiCompareText, так и winapi CompareTextW) представляют собой все "ß" с "ss" и каждый "ö" с нормальным "o"... поэтому, если я беру эти результаты выше и на поиск и замените, как описано, я получаю...
- arss asss asss Asss no no o on oo oo ooo ooo op po ss SS ssass ssbss sss Sssa Sssb ssss ssss SSSS ssssss ssssss SSssss ssz sszss z zzz
Выглядит довольно правильно для меня! И это всегда было.
Я чрезвычайно благодарен за все предоставленные советы и очень сожалею, что потратил ваше время так. Эти немецкие ß заставили меня смутить, никогда не было ничего плохого в встроенной функции дельфи или что-то еще. Это было похоже на то, что было. Я допустил ошибку, объединив их с обычными 's' в моих тестовых данных, любое другое письмо не создало бы эту иллюзию неупорядоченности! Улыбка ß заставила меня выглядеть дураком! ßs!
Rudy и lkessler мы оба особенно полезны, и то и другое, я должен принять lkessler ответ как самый правильный, извините Руди.