Я пытаюсь отсортировать массив / списки / что угодно из данных на основе строковых значений Юникода, которые содержат неанглийские символы, я хочу, чтобы они сортировались правильно по алфавиту.
Я написал много кода (D2010, win XP), который, как мне показалось, был довольно солидным для будущей интернационализации, но это не так.Все это с использованием типа данных unicodestring (string), который до сих пор я только что помещал английские символы в строки unicode.
Кажется, я должен признать очень серьезную ошибку Unicode.Я поговорил с моим немецким другом и попробовал некоторые немецкие ß (ß - это 'ss' и должно следовать после S и перед T в алфавите), а также ö и т.д. (обратите внимание на умляут), и ни один из моих алгоритмов сортировки больше не работает.Результаты очень запутаны.Мусор.
С тех пор я много читал и узнал много неприятных вещей, касающихся сопоставления юникода.Все выглядит мрачно, гораздо мрачнее, чем я когда-либо ожидал, я серьезно все испортил.Я надеюсь, что я что-то упускаю, и вещи на самом деле не так мрачны, как кажутся в настоящее время.Я возился с просмотром вызовов Windows API (RtlCompareUnicodeString) безуспешно (ошибки защиты), я не мог заставить его работать.Проблема с вызовами API, которую я узнал, заключается в том, что они меняются на различных новых платформах Windows, а также в связи с тем, что Delphi скоро станет кроссплатформенным, с Linux позже, мое приложение - клиент-сервер, поэтому я должен быть обеспокоен этой ситуацией, но сейчасэто (плохо), я был бы благодарен за любой прогресс вперед, то есть, специфичный для win api.
Является ли использование функции win api RtlCompareUnicodeString очевидным решением?Если это так, я действительно должен повторить попытку с этим, но я был озадачен всеми проблемами, связанными с сопоставлением юникода, и я не совсем понял, что мне следует делать, чтобы сравнивать эти строки таким образом.
Я узнал о проекте с открытым исходным кодом IBM ICU c ++, для него есть обертка delphi, хотя и для более старой версии ICU.Кажется, это очень всеобъемлющее решение, которое не зависит от платформы.Конечно, я не могу смотреть на создание оболочки Delphi для этого (или обновлять существующую), чтобы получить хорошее решение для сопоставления Unicode?
Я был бы очень рад услышать советы на двух уровнях: -
A) Специально для переносимого решения для Windows, я был бы рад, что на данный момент, забудьте о последствиях клиент-сервер!Б) Более портативное решение, которое защищено от различных вариаций функций API Unicode XP / Vista / Win7, поэтому я могу найти хорошую поддержку для поддержки Mac XE2 и будущей поддержки Linux, не говоря уже о сложностях клиент-сервер.
Между прочим, я действительно не хочу делать «готовые» решения, сканировать строки перед сравнением и заменять некоторые хитрые символы и т. Д., О которых я читал.Я привел немецкий пример выше, это всего лишь пример, я хочу, чтобы он работал на всех (или, по крайней мере, на большинстве, дальневосточном, русском) языках, я не хочу делать обходные пути для конкретного языка или двух.Мне также не нужны никакие советы по алгоритмам сортировки, они в порядке, просто бит сравнения строк неправильный.
Надеюсь, я упускаю / делаю что-то глупое, все это выглядит как головная боль.
Спасибо.
РЕДАКТИРОВАТЬ, Руди, вот как я пытался вызвать 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-интерфейсы напрямую, это мое лучшее предположение.
О вашей функции API StringCompareEx.Это выглядело действительно хорошо, но доступно только на Vista +, я использую XP.StringCompare работает на XP, но это не Unicode!
Подводя итог, можно сказать, что основная задача в данный момент - сравнить две строки и сделать это в соответствии с порядком сортировки символов, указанным в текущей локали Windows.
Кто-нибудь может сказать наверняка, должен ли ansicomparetext сделать это или нет?Это не работает для меня, но другие сказали, что это должно, и другие вещи, которые я прочитал, предполагают, что это должно.
Это то, что я получаю с 31 тестовой строкой, когда использую AnsiCompareText в немецком языке (с разделителями пробелами - ни одна строка не содержит пробелов): -
- arß Asß asß aßs no nöööönoo öö oöo öoö pö ss SS ßaß ßbß sß Sßa Sßb ßß ssss SSSS ßßß sssßß SSßß ßz ßzß z zzz
EDIT 2.
до сих пор слышуесли бы я ожидал, что AnsiCompareText будет работать с использованием информации о локали, как сказал lkessler, и lkessler также уже публиковал информацию по этим вопросам раньше, и, похоже, уже проходил через это раньше.
Однако, следуя совету Руди, я имеютакже проверял CompareStringW - который разделяет ту же документацию с CompareString , так что это НЕ не-Unicode, как я уже говорил ранее.
Даже если 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 и о том, что я делаю не так с приведенным выше вызовом API CompareStringW.Спасибо.
EDIT 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 ßßß sssßs SSßß ßzß z zzz
*1065* Вы также можете упомянуть, что вы не можете упоминать менярадость, когда я понял, что порядок сортировки является ПРАВИЛЬНЫМ, И ЭТО БЫЛО ПРАВИЛЬНО ВЕРНУТЬСЯ В НАЧАЛЕ!Мне больно говорить это, но с самого начала не было никаких проблем - все это связано с моим отсутствием знания немецкого языка.Я поверил, что сортировка была неправильной, так как вы можете видеть выше строки, начинающиеся с S, затем позже они начинаются с ß, затем снова s и возвращаются к ß и так далее.Ну, я не могу говорить по-немецки, но я все еще мог ясно видеть, что они не были отсортированы правильно - мой немецкий друг сказал мне, что идет после S и до T ... Я НЕПРАВИЛЬНО!Что происходит, так это то, что строковые функции (и AnsiCompareText, и winapi CompareTextW) заменяют каждое 'ß' на 'ss', а каждое 'ö' - на нормальное 'o' ... так что если я возьму результаты выше и для поискаи заменить, как описано, я получаю ...
- arss asss asss Asss нет нет на oo oo ooo ooo op po ss SS ssass ssbss sss Sssa Sssb ssss ssss SSSS ssssss ssssss SSssss ssz sszss z zzz
Выглядит довольно правильно для меня!И так было всегда.
Я чрезвычайно благодарен за все приведенные советы и очень сожалею, что потратил впустую ваше время, как это.Эти немецкие ß запутали меня, никогда не было ничего плохого со встроенной функцией delphi или чем-то еще.Это просто выглядело как было.Я допустил ошибку, объединив их с обычными 's' в моих тестовых данных, любое другое письмо не создало бы эту иллюзию несортировки!Из-за волнистой особы я выглядела глупо!ßs!
Руди и lkessler, мы оба особенно полезны, оба, я должен принять ответ lkessler как самый правильный, извините, Руди.