mundo - Clasificación de texto multilingüe en Perl, en Windows, utilizando la configuración regional
hola mundo en python (2)
Win32 :: OLE :: NLS le da acceso a esa parte del sistema. Le proporciona CompareString
y las herramientas necesarias para obtener la id de configuración regional necesaria.
En caso de que quiera / necesite localizar la documentación del sistema, la llamada al sistema subyacente se llama CompareStringEx
.
Estoy construyendo una pieza de software para clasificar índices de libros en diferentes idiomas. Utiliza Perl y claves fuera de la configuración regional. Lo estoy desarrollando en Unix, pero debe ser portátil para Windows. Si esto funciona en principio, o confiando en la configuración regional, ¿estoy ladrando al árbol equivocado? En pocas palabras, Windows realmente es donde necesito que esto funcione, pero me siento más cómodo desarrollando en mi entorno UNIX.
Suponiendo que su punto de partida es Unicode, porque ha tenido mucho cuidado de decodificar todos los datos entrantes sin importar cuál sea su codificación nativa, entonces es fácil de usar para el módulo Unicode::Collate
como punto de partida.
Si desea una adaptación regional, entonces probablemente desee comenzar con Unicode::Collate::Locale
.
Decodificación en Unicode
Si se ejecuta en un entorno totalmente UTF8, esto es fácil, pero si está sujeto a las vicisitudes de los denominados "locales" (o incluso cosas peores que Microsoft llama "páginas de códigos"), entonces puede querer para obtener el módulo CPAN Encode::Locale
para que lo ayude. Por ejemplo:
use Encode;
use Encode::Locale;
# use "locale" as an arg to encode/decode
@ARGV = map { decode(locale => $_) } @ARGV;
# or as a stream for binmode or open
binmode $some_fh, ":encoding(locale)";
binmode STDIN, ":encoding(console_in)" if -t STDIN;
binmode STDOUT, ":encoding(console_out)" if -t STDOUT;
binmode STDERR, ":encoding(console_out)" if -t STDERR;
(Si fuera yo, solo usaría ":utf8"
para la salida).
Intercalación estándar, además de configuraciones regionales y adaptación
El punto es que una vez que tiene todo decodificado en formato interno de Perl, puede usar Unicode::Collate
y Unicode::Collate::Locale
en él. Estos pueden ser realmente fáciles:
use v5.14;
use utf8;
use Unicode::Collate;
my @exes = qw( x⁷ x⁰ x⁸ x³ x⁶ x⁵ x⁴ x² x⁹ x¹ );
@exes = Unicode::Collate->new->sort(@exes);
say "@exes";
# prints: x⁰ x¹ x² x³ x⁴ x⁵ x⁶ x⁷ x⁸ x⁹
O pueden ser muy elegantes. Aquí hay uno que trata de lidiar con títulos de libros: quita artículos principales y números de cero.
my $collator = Unicode::Collate->new(
--upper_before_lower => 1,
--preprocess => {
local $_ = shift;
s/^ (?: The | An? ) /h+ //x; # strip articles
s/ ( /d+ ) / sprintf "%020d", $1 /xeg;
return $_;
};
);
Ahora solo usa el método de ordenación de ese objeto para ordenar.
A veces necesitas dar la vuelta al orden. Por ejemplo:
my $collator = Unicode::Collate->new();
for my $rec (@recs) {
$rec->{NAME_key} =
$collator->getSortKey( $rec->{NAME} );
}
@srecs = sort {
$b->{AGE} <=> $a->{AGE}
||
$a->{NAME_key} cmp $b->{NAME_key}
} @recs;
La razón por la que tiene que hacer eso es porque está ordenando un registro con varios campos. La tecla de clasificación binaria le permite usar el operador cmp
en los datos que han pasado por su objeto de clasificación elegido / personalizado.
El constructor completo del objeto de clasificación tiene todo esto para una sintaxis formal:
$Collator = Unicode::Collate->new(
UCA_Version => $UCA_Version,
alternate => $alternate, # alias for ''variable''
backwards => $levelNumber, # or /@levelNumbers
entry => $element,
hangul_terminator => $term_primary_weight,
highestFFFF => $bool,
identical => $bool,
ignoreName => qr/$ignoreName/,
ignoreChar => qr/$ignoreChar/,
ignore_level2 => $bool,
katakana_before_hiragana => $bool,
level => $collationLevel,
minimalFFFE => $bool,
normalization => $normalization_form,
overrideCJK => /&overrideCJK,
overrideHangul => /&overrideHangul,
preprocess => /&preprocess,
rearrange => /@charList,
rewrite => /&rewrite,
suppress => /@charList,
table => $filename,
undefName => qr/$undefName/,
undefChar => qr/$undefChar/,
upper_before_lower => $bool,
variable => $variable,
);
Pero generalmente no tienes que preocuparte por casi ninguno de esos. De hecho, si desea adaptar el entorno nacional específico del país utilizando los datos CLDR, debe usar Unicode::Collate::Locale
, que agrega exactamente un parámetro más al constructor: locale => $country_code
.
use Unicode::Collate::Locale;
$coll = Unicode::Collate::Locale->
new(locale => "fr");
@french_text = $coll->sort(@french_text);
¿Ves lo fácil que es eso?
Pero puedes hacer otras cosas geniales también.
use Unicode::Collate::Locale;
my $Collator = new Unicode::Collate::Locale::
locale => "de__phonebook",
level => 1,
normalization => undef,
;
my $full = "Ich müß Perl studieren.";
my $sub = "MUESS";
if (my ($pos,$len) = $Collator->index($full, $sub)) {
my $match = substr($full, $pos, $len);
say "Found match of literal ‹$sub› in ‹$full› as ‹$match›";
}
Cuando se ejecuta, eso dice:
Found match of literal ‹MUESS› in ‹Ich müß Perl studieren.› as ‹müß›
Estas son las configuraciones regionales disponibles a partir de v0.96 del módulo Unicode::Collate::Locale
, tomadas de su página de manual:
locale name description
--------------------------------------------------------------
af Afrikaans
ar Arabic
as Assamese
az Azerbaijani (Azeri)
be Belarusian
bg Bulgarian
bn Bengali
bs Bosnian
bs_Cyrl Bosnian in Cyrillic (tailored as Serbian)
ca Catalan
cs Czech
cy Welsh
da Danish
de__phonebook German (umlaut as ''ae'', ''oe'', ''ue'')
ee Ewe
eo Esperanto
es Spanish
es__traditional Spanish (''ch'' and ''ll'' as a grapheme)
et Estonian
fa Persian
fi Finnish (v and w are primary equal)
fi__phonebook Finnish (v and w as separate characters)
fil Filipino
fo Faroese
fr French
gu Gujarati
ha Hausa
haw Hawaiian
hi Hindi
hr Croatian
hu Hungarian
hy Armenian
ig Igbo
is Icelandic
ja Japanese [1]
kk Kazakh
kl Kalaallisut
kn Kannada
ko Korean [2]
kok Konkani
ln Lingala
lt Lithuanian
lv Latvian
mk Macedonian
ml Malayalam
mr Marathi
mt Maltese
nb Norwegian Bokmal
nn Norwegian Nynorsk
nso Northern Sotho
om Oromo
or Oriya
pa Punjabi
pl Polish
ro Romanian
ru Russian
sa Sanskrit
se Northern Sami
si Sinhala
si__dictionary Sinhala (U+0DA5 = U+0DA2,0DCA,0DA4)
sk Slovak
sl Slovenian
sq Albanian
sr Serbian
sr_Latn Serbian in Latin (tailored as Croatian)
sv Swedish (v and w are primary equal)
sv__reformed Swedish (v and w as separate characters)
ta Tamil
te Telugu
th Thai
tn Tswana
to Tonga
tr Turkish
uk Ukrainian
ur Urdu
vi Vietnamese
wae Walser
wo Wolof
yo Yoruba
zh Chinese
zh__big5han Chinese (ideographs: big5 order)
zh__gb2312han Chinese (ideographs: GB-2312 order)
zh__pinyin Chinese (ideographs: pinyin order) [3]
zh__stroke Chinese (ideographs: stroke order) [3]
zh__zhuyin Chinese (ideographs: zhuyin order) [3]
Locales according to the default UCA rules include chr (Cherokee), de (German), en (English), ga (Irish), id (Indonesian),
it (Italian), ka (Georgian), ms (Malay), nl (Dutch), pt (Portuguese), st (Southern Sotho), sw (Swahili), xh (Xhosa), zu
(Zulu).
Note
[1] ja: Ideographs are sorted in JIS X 0208 order. Fullwidth and halfwidth forms are identical to their regular form. The
difference between hiragana and katakana is at the 4th level, the comparison also requires "(variable => ''Non-ignorable'')",
and then "katakana_before_hiragana" has no effect.
[2] ko: Plenty of ideographs are sorted by their reading. Such an ideograph is primary (level 1) equal to, and secondary
(level 2) greater than, the corresponding hangul syllable.
[3] zh__pinyin, zh__stroke and zh__zhuyin: implemented alt=''short'', where a smaller number of ideographs are tailored.
Note: ''pinyin'' is in latin, ''zhuyin'' is in bopomofo.
Así que, en resumen, el truco principal es descodificar los datos locales en una representación Unicode uniforme, y luego utilizar una ordenación determinista, posiblemente adaptada, que no dependa de la configuración aleatoria de la ventana de la consola del usuario para un comportamiento correcto.
Nota: Todos estos ejemplos, aparte de la cita de la página de manual, se eliminan amorosamente de la 4ª edición de Programming Perl , con el amable permiso de su autor. :)