latinos coding caracteres acentos delphi unicode collation

delphi - coding - ¿Cómo comparo las cadenas de Unicode que contienen caracteres que no están en inglés para clasificar de forma alpabéticamente?



python unicode acentos (4)

¿Has probado AnsiCompareText? A pesar de que se llama "Ansi", creo que recurre a una rutina de comparación Unicode-capaz específica del sistema operativo ...

También debería protegerlo de las dependencias multiplataforma (siempre que Embarcadero proporcione una versión compatible en los distintos sistemas operativos a los que se dirigen).

No sé qué tan bien funciona la comparación con las diversas formas extrañas de Unicode para codificar cadenas, pero pruébelo y déjenos saber el resultado ...

Estoy tratando de ordenar la matriz / listas / lo que sea de los datos en función de los valores de cadena de Unicode que contienen caracteres que no están en inglés, quiero que estén ordenados correctamente en orden alfabético.

He escrito muchos códigos (D2010, win XP), que me parecieron bastante sólidos para la futura internacionalización, pero no lo es. Es todo lo que usa el tipo de datos Unicodestring (cadena), que hasta ahora acabo de poner caracteres en inglés en las cadenas Unicode.

Parece que tengo que confesar que he cometido un grave error Unicode. Hablé con mi amigo alemán y probé algunos ß''s alemanes, (ß es ''ss'' y debería aparecer después de S y antes de T en el alfabeto) y ö''s etc (note la diéresis) y ninguno de mis algoritmos de clasificación ya funciona. Los resultados están muy mezclados. Basura.

Desde entonces he estado leyendo mucho y he aprendido muchas cosas desagradables con respecto a la intercalación de Unicode. Las cosas se ven sombrías, mucho más sombrías de lo que nunca había esperado, lo he estropeado seriamente. Espero que me esté perdiendo algo y las cosas no sean tan sombrías como parecen en la actualidad. He estado dando vueltas mirando las llamadas de la API de Windows (RtlCompareUnicodeString) sin éxito (fallas de protección), no pude hacer que funcionara. El problema con las llamadas a la API que aprendí es que cambian en varias plataformas de Windows más nuevas, y que Delphi se va a cruzar pronto, con Linux más tarde, mi aplicación es un servidor cliente, así que debo preocuparme por esto, pero la situación es lo que es (malo) que agradecería cualquier avance, es decir, ganar api específico.

¿El uso de la función win api RtlCompareUnicodeString es una solución obvia? Si es así, debería intentarlo de nuevo, pero me han sorprendido todos los problemas relacionados con la intercalación de Unicode y no tengo claro en absoluto qué debería hacer para comparar estas cadenas de esta manera.

Me enteré del proyecto de código abierto de IBM ICU c ++, hay una envoltura de Delphi para ello, aunque para una versión anterior de ICU. Parece una solución muy completa que es independiente de la plataforma. ¿Seguramente no puedo crear un contenedor delphi para esto (o actualizar el existente) para obtener una buena solución para la intercalación de Unicode?

Me encantaría escuchar consejos en dos niveles:

A) Una solución no portátil específica de Windows, me alegraría saber que en este momento, ¡olvide las ramificaciones del servidor cliente! B) Una solución más portátil que es inmune a las diversas variaciones de XP / vista / win7 de las funciones de la API de Unicode, por lo que me pone en una buena posición para el soporte de XE2 para mac y para el futuro soporte de Linux, por no mencionar las complicaciones del servidor cliente.

Por cierto, realmente no quiero estar haciendo soluciones ''make-do'', escaneando cadenas antes de la comparación y reemplazando ciertos caracteres difíciles, etc., sobre los cuales he leído. Di el ejemplo de alemán anterior, eso es solo un ejemplo, quiero que funcione para todos (o al menos la mayoría, en el lejano oriente, ruso), no quiero hacer soluciones para un idioma específico o dos. Tampoco necesito ningún consejo sobre los algoritmos de clasificación, están bien, es solo el bit de comparación de cadena que está mal.

Espero que me esté perdiendo / haciendo algo estúpido, todo esto parece ser un dolor de cabeza.

Gracias.

EDIT, Rudy, aquí es cómo intentaba llamar a RtlCompareUnicodeString. Perdón por el retraso, he estado teniendo un tiempo horrible con esto.

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.

Me doy cuenta de que esto es probablemente incorrecto, no estoy acostumbrado a llamar directamente a las citas, esta es mi mejor suposición.

Acerca de su función StringCompareEx api. Eso se veía realmente bien, pero está disponible solo en Vista +, estoy usando XP. StringCompare está en XP, pero eso no es Unicode!

Para recapitular, la tarea básica que está en marcha es comparar dos cadenas y hacerlo en función del orden de caracteres especificado en la configuración regional de Windows actual.

¿Alguien puede decir con seguridad si ansicomparetext debería hacer esto o no? No me funciona, pero otros han dicho que debería, y otras cosas que he leído sugieren que debería.

Esto es lo que obtengo con 31 cadenas de prueba cuando uso AnsiCompareText cuando está en la configuración regional alemana (espacio delimitado - no hay cadenas que contengan espacios):

  • arß Asß asß aßs no nö ö ö ön oö öö oöo öoö öp pö ss SS ßaß ßbß sß Sßa Sßb ßß ssss SSSS ßßß ssßß sßßß sßß ßzß z zzz

EDITAR 2.

Todavía estoy ansioso por saber si debo esperar que AnsiCompareText funcione con la información del entorno local, como lo dijo lkessler, y lkessler también ha publicado sobre estos temas antes y parece que ya ha pasado por esto.

Sin embargo, siguiendo los consejos de Rudy, también he estado revisando CompareStringW, que comparte la misma documentación con CompareString , por lo que NO es unicode como he dicho anteriormente.

Incluso si AnsiCompareText no va a funcionar, aunque creo que debería hacerlo, la función win32api CompareStringW debería funcionar. Ahora he definido mi función de API, y puedo llamarlo, y obtengo un resultado, y ningún error ... ¡pero siempre obtengo el mismo resultado independientemente de las cadenas de entrada! Devuelve 1 cada vez, lo que significa menos que. Aquí está mi código

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;

Siento que estoy llegando a algún lugar ahora después de mucho dolor. Me encantaría saber acerca de AnsiCompareText, y lo que estoy haciendo mal con la llamada de API CompareStringW anterior. Gracias.

EDITAR 3

En primer lugar, arreglé la llamada a la API para CompareStringW, pasaba por @mystring cuando debería hacer PString (mystring). Ahora todo funciona correctamente.

r:=comparestringw(LOCALE_USER_DEFAULT,0,pstring(k),-1,pstring(l),-1);

Ahora, puedes imaginar mi consternación cuando todavía obtuve el mismo resultado que al principio ...

  • arß asß aßs Asß no nö ö ö ön oö öö oöo öoö öp pö ss SS ßaß ßbß sß Sßa Sßb ßß ssss SSSS ßßß ssßß sßßß ßzß zß

También puedes imaginar mi EXTREMA consternación por no mencionar la alegría simultánea cuando me di cuenta de que el orden de clasificación ES CORRECTO, ¡Y FUE CORRECTO DE VUELTA AL COMIENZO! Es un poco enfermizo decirlo, pero nunca hubo ningún problema en primer lugar, todo esto se debe a mi falta de conocimiento alemán. Creía que el tipo era incorrecto, ya que puedes ver que la cadena anterior comienza con S, luego, comienzan con ß, luego s otra vez y de nuevo a ß y así sucesivamente. Bueno, no puedo hablar en alemán, sin embargo, todavía pude ver claramente que no se clasificaron correctamente. Mi amigo alemán me dijo que venía después de S y antes de T ... ¡Estaba equivocado! Lo que está sucediendo es que las funciones de cadena (tanto AnsiCompareText como winapi CompareTextW) están SUSTITUYENDO cada ''ß'' con ''ss'', y cada ''ö'' con una ''o'' normal ... así que si tomo esos resultados arriba y en una búsqueda y reemplazar según lo descrito me sale ...

  • 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 zzzz

Me parece bastante correcto! Y siempre fue así.

Estoy extremadamente agradecido por todos los consejos dados, y siento mucho haber perdido su tiempo de esta manera. Esos ß alemanes me han confundido, nunca hubo nada malo en la función delphi incorporada o cualquier otra cosa. Simplemente parecía que había. Cometí el error de combinarlos con los ''s'' normales en mis datos de prueba, ¡cualquier otra carta no habría creado esta ilusión de falta de clasificación! ¡Los garabatos ß me han hecho parecer un tonto! ßs!

Rudy y lkessler, ambos somos especialmente útiles, y ambos, tengo que aceptar la respuesta de lkessler como la más correcta, lo siento Rudy.


En Unicode, el orden numérico de los caracteres ciertamente no es la secuencia de clasificación. AnsiCompareText, como lo menciona HeartWare, toma en cuenta los detalles de la configuración regional al comparar caracteres, pero, como descubrió, no hace nada en relación con el orden de clasificación. Lo que está buscando se llama la secuencia de intercalación de un idioma, que especifica el orden de clasificación alfabético para un idioma que tenga en cuenta los signos diacríticos, etc. Estaban implícitos en las antiguas páginas del Código Ansi, aunque tampoco tenían en cuenta la diferencia entre los idiomas que utilizan el mismo conjunto de caracteres.

Revisé los documentos D2010. Aparte de algunos componentes TIB * no encontré ningún enlace. El generador de C ++ parece tener una función de comparación que toma en cuenta la intercalación, pero no es de mucha utilidad en Delphi. Probablemente tendrás que usar algunas funciones de la API de Windows directamente.

Docs:

El artículo de ''Clasificación "de todos los componentes" es de Michael Kaplan, alguien que tiene un gran conocimiento profundo de todo lo relacionado con Unicode y todas las complejidades de varios idiomas. Su blog ha sido de gran valor para mí cuando pasé de D2006 a D2009.


Intente usar CompareStr para CompareStr entre mayúsculas y minúsculas, o CompareText para CompareText entre mayúsculas y minúsculas si desea que su ordenación sea exactamente igual en cualquier localidad.

Y use AnsiCompareStr para AnsiCompareStr entre mayúsculas y minúsculas, o AnsiCompareText para AnsiCompareText entre mayúsculas y minúsculas si desea que sus clasificaciones sean específicas de la ubicación del usuario.

Vea: ¿Cómo puedo hacer que TStringList clasifique de forma diferente en Delphi para obtener más información sobre esto?


Usted dijo que tenía problemas para llamar a las llamadas de la API de Windows. ¿Podría publicar el código para que la gente pueda ver por qué falló? No es tan difícil como parece, pero requiere cierto cuidado. ISTM que RtlCompareUnicodeStrings() es un nivel demasiado bajo.

He encontrado algunas soluciones:

No portátil

Podría utilizar la función API de Windows CompareStringEx . Esto se comparará utilizando tipos de colación específicos de Unicode. Puede especificar cómo desea que se haga esto (ver enlace). Requiere cadenas anchas, es decir, punteros PWideChar a ellos. Si tienes problemas para llamarlo, dale un saludo y trataré de agregar un código de demostración.

Más o menos portátil

Para hacer esto más o menos portátil, podría escribir una función que compare dos cadenas y usar definiciones condicionales para elegir las diferentes API de comparación para la plataforma.