2011-05-15 22 views
8

¿es posible ordenar correctamente cadenas con caracteres nacionales en Haskell (GHC)? En otras palabras, ¿es correcta la clasificación de Chars según la configuración regional actual?Ordenando y comparando cadenas por localidades en Haskell?

Encontré el módulo de ICU solamente, pero requiere que se instale una biblioteca adicional porque no es una parte estándar de las distribuciones de Linux. Me gustaría una solución basada en la biblioteca C de POSIX (similar a glibc), por lo que no habrá problemas con el manejo de la dependencia adicional.

+0

Se puede escribir una FFI unión a 'wcscoll', pero el uso de' texto icu' es tanto más agradable y probablemente más correcta. – hammar

+0

Buena pregunta y buena respuesta. Las cosas humanas nunca son una función pura. –

Respuesta

13

Forma recomendada: Texto-UCI

La forma recomendada para procesar robusta cuerdas de una manera sensible a la localidad es a través de text y text-icu, como has visto. La biblioteca text se proporciona en el conjunto de bibliotecas estándar, Haskell Platform.

Un ejemplo, clasificar las cadenas turcas:

{-# LANGUAGE OverloadedStrings #-} 

import Data.Text.IO as T 
import Data.Text.ICU as T 
import Data.List  (sortBy) 

main = do 
    let trLocale = T.Locale "tr-TR" 
     str  = "ÇIİĞÖŞÜ" 
     strs  = take 10 (cycle $ T.toLower trLocale str : str : []) 

    mapM_ T.putStrLn (sortBy (T.compare [T.FoldCaseExcludeSpecialI]) strs) 

parece correcta ordenar por lexicographic ordering según la configuración regional, después correctamente inferior carcasa de la cadena turca:

*Main> main 
ÇIİĞÖŞÜ 
ÇIİĞÖŞÜ 
ÇIİĞÖŞÜ 
ÇIİĞÖŞÜ 
ÇIİĞÖŞÜ 
çıiğöşü 
çıiğöşü 
çıiğöşü 
çıiğöşü 
çıiğöşü 

no se utiliza el texto: paquete de icu

Ha preguntado en su pregunta para evitar soluciones que usan add bibliotecas locales, aparte de lo que ofrece Posix. Mientras que el texto-icu es fácilmente instalable desde Hackage (cabal install text-icu), depende de la biblioteca de la ICU C, que no está disponible en todas partes. Además, no existe una alternativa de Posix que sea tan robusta o integral. Finalmente, text-icu es el único paquete que realiza conversiones correctamente en caracteres de varios caracteres.

Dado esto, sin embargo, el construido en Char y String tipos en Haskell proporcionar Data.Char, cuyos valores representan Unicode, y con funciones que will do Unicode case conversion, de una manera locale-insensible, utilizando the wchar_t functions definido por el Open Group. Además, podemos hacer IO en Handles en una forma sensible al entorno local (de texto).

import System.IO 
import Data.Char 
import Data.List (sort) 

main = do 
    t <- mkTextEncoding "UTF-8" 
    hSetEncoding stdout t 

    let str  = "ÇIİĞÖŞÜ" 
     strs  = take 10 (cycle $ map toLower str : str : []) 

    mapM_ putStrLn (sort strs) 

De hecho, GHC utilizará la configuración regional de texto por defecto para IO (por ejemplo, UTF-8). Para muchos problemas, esto probablemente dará la respuesta correcta. Solo debe tener en cuenta que también será incorrecto en muchos casos, ya que no es posible ser correcto sin un procesamiento masivo de texto y un rico soporte de conversión y comparación.

*Main> main 
ÇIİĞÖŞÜ 
ÇIİĞÖŞÜ 
ÇIİĞÖŞÜ 
ÇIİĞÖŞÜ 
ÇIİĞÖŞÜ 
çiiğöşü 
çiiğöşü 
çiiğöşü 
çiiğöşü 
çiiğöşü 

+1

Y observe que 'i' es diferente en la solución de Char. –

+2

¿No sería más correcto usar [estas funciones] (http://hackage.haskell.org/packages/archive/text-icu/0.6.3.3/doc/html/Data-Text-ICU.html#g : 9) para la intercalación específica de la configuración regional – hammar

+0

También tenga en cuenta que toUpper on 'Char' solo genera una conversión de caracteres amplia, en función de la configuración regional' LC_CTYPE'. Por lo tanto, es solo parcialmente consciente de la configuración regional. Y como se mencionó, falla para las conversiones multi-char. –