Как сравнить строки Unicode, содержащие неанглийские символы, для сортировки в алфавитном порядке?

Я пытаюсь отсортировать массивы / списки / любые данные на основе строковых значений в них, содержащих неанглийские символы, я хочу, чтобы они были правильно отсортированы по алфавиту.

Я написал много кода (D2010, win XP), который, на мой взгляд, был достаточно надежным для будущей интернационализации, но это не так. Все это использует тип данных unicodestring (строка), который до сих пор я просто вставлял английские символы в строки Unicode.

Кажется, я должен признать, что допустил очень серьезную ошибку Unicode. Я поговорил со своим немецким другом и попробовал несколько немецких ß (ß - это 'ss' и должен стоять после S и перед T в алфавите), и ö и т. Д. (Обратите внимание на умляут), и ни один из моих алгоритмов сортировки больше не работает. Результаты очень смешанные. Мусор.

С тех пор я много читал и узнал много неприятных вещей относительно сортировки юникода. Все выглядит мрачно, намного мрачнее, чем я ожидал, я серьезно все испортил. Надеюсь, я чего-то упускаю, и на самом деле все не так мрачно, как кажется сейчас. Я возился с просмотром вызовов api Windows (RtlCompareUnicodeString) безуспешно (ошибки защиты), я не мог заставить его работать. Проблема с вызовами API, которые я узнал, заключается в том, что они меняются на различных более новых платформах Windows, а также в связи с тем, что delphi скоро перейдет на другую платформу, а позже с Linux, мое приложение является клиентским сервером, поэтому мне нужно беспокоиться об этом, но с учетом ситуации это (плохо) Я был бы благодарен за любой прогресс, то есть за конкретный win api.

Использует ли win api функцию RtlCompareUnicodeString для очевидного решения? Если это так, мне действительно стоит попробовать еще раз с этим, но я был озадачен всеми проблемами, связанными с сортировкой Unicode, и я вообще не понимаю, что мне делать, чтобы сравнивать эти строки таким образом.

Я узнал о проект с открытым исходным кодом IBM ICU c ++, для него есть оболочка delphi, хотя и для более старой версии ICU. Это кажется очень комплексным решением, не зависящим от платформы. Конечно, я не могу смотреть на создание оболочки delphi для этого (или обновление существующей), чтобы получить хорошее решение для сортировки Unicode?

Я был бы чрезвычайно рад услышать советы на двух уровнях: -

A) Непереносимое решение для Windows, я был бы рад, если бы на данный момент забыл о разветвлениях клиент-сервер! Б) Более портативное решение, которое невосприимчиво к различным вариантам функций unicode api для XP / Vista / win7, поэтому мне очень пригодится поддержка Mac XE2 и будущая поддержка Linux, не говоря уже об осложнениях с клиентским сервером.

Btw Я действительно не хочу заниматься «самодельными» решениями, сканировать строки перед сравнением и заменять некоторые сложные символы и т. Д., О которых я читал. Я привел пример немецкого языка выше, это просто пример, я хочу, чтобы он работал для всех (или, по крайней мере, для большинства, дальневосточного, русского) языков, я не хочу делать обходные пути для одного или двух конкретных языков. Мне также не нужны советы по алгоритмам сортировки, они в порядке, это просто неправильный бит сравнения строк.

Надеюсь, я упускаю / делаю что-то глупое, все это выглядит головной болью.

Спасибо вы.


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-функции, это мое лучшее предположение.

О вашей функции API StringCompareEx. Выглядело неплохо, но работает только в Vista +, я использую XP. StringCompare находится в XP, но это не Unicode!

Напомним, основная задача заключается в сравнении двух строк,и делать это на основе порядка сортировки символов, указанного в текущем языковом стандарте Windows.

Может ли кто-нибудь точно сказать, должен ли ansicomparetext делать это или нет? Это не работает для меня, но другие говорили, что это должно быть, и другие вещи, которые я читал, предполагают, что это должно быть.

Это то, что я получаю с 31 тестовой строкой при использовании AnsiCompareText в немецком языке (с разделением пробелами - строки не содержат пробелов): -

  • 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 также писал о эти предметы раньше и, кажется, уже проходили через это раньше.

Однако, следуя совету Руди, я также проверял 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 и о том, что я делаю не так с приведенным выше вызовом API-интерфейса CompareStringW. Спасибо.


РЕДАКТИРОВАТЬ 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

Вы также можете вообразить мое НЕВЕРОЯТНОЕ смятение, не говоря уже об одновременной радости, когда я понял, что порядок сортировки ПРАВИЛЬНЫЙ, и ЭТО БЫЛО ПРАВИЛЬНО В НАЧАЛЕ! Мне неприятно говорить это, но, во-первых, никаких проблем не было - все из-за моего незнания немецкого языка. Я подумал, что сортировка была неправильной, так как вы можете видеть, что строка выше начинается с S, затем они начинаются с ß, затем снова 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

Мне кажется, это очень правильно! И так было всегда.

Я чрезвычайно благодарен за все данные советы и очень сожалею, что потратил ваше время на это. Эти немецкие ß сбили меня с толку, никогда не было ничего плохого со встроенной функцией delphi или чем-то еще. Просто выглядело так, как будто было. Я допустил ошибку, объединив их с нормальными буквами в моих тестовых данных, любая другая буква не создала бы эту иллюзию несортированности! Волнистые ß заставили меня выглядеть дураком! ßs!

Руди и Икесслер, мы оба особенно полезны, оба, я должен принять ответ Лкесслера как наиболее правильный, извини, Руди.

18
задан csharpdefector 14 August 2011 в 02:07
поделиться