2015-11-01 29 views
8

Unicode girişli locale kütüphanesi kullanırken garip bir davranış yaşıyorum. Ben Python 3.3, 3.4 ve 3.5 bu gördükUnicode karakter, locale.strxfrm çağrılıyor menzil aralığında değil

>>> x = '\U0010fefd' 
>>> ord(x) 
1113853 
>>> ord('\U0010fefd') == 0X10fefd 
True 
>>> ord(x) <= 0X10ffff 
True 
>>> import locale 
>>> locale.strxfrm(x) 
'\U0010fefd' 
>>> locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') 
'en_US.UTF-8' 
>>> locale.strxfrm(x) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: character U+110000 is not in range [U+0000; U+10ffff] 

: Aşağıda minimum çalışma örneğidir. Python 2.7'de bir hata alamıyorum.

Görebildiğim kadarıyla, benim unicode girdim uygun unicode aralığı içerisindedir, bu nedenle 'en_US.UTF-8' işlevini kullanırken bir şekilde dahili bir şey girişi menzil dışına taşıyor gibi görünmektedir.

Mac OS X çalıştırıyorum ve bu davranış http://bugs.python.org/issue23195 ... ile ilgili olabilir, ancak bu hatanın yalnızca yükseltilmiş bir istisna değil, yanlış sonuç olarak ortaya çıkacağı izlenimindeydim. SLES 11 makinemde çoğalamıyorum ve diğerleri Ubuntu, Centos veya Windows üzerinde çoğaltılamadıklarını onaylıyor. Yorumlardaki diğer işletim sistemlerini duymak öğretici olabilir.

Burada biri kaputun altında neler olabileceğini açıklayabilir mi?

+0

Ubuntu'da yeniden oluşturamıyorum. 'locale.strxfrm (x)' 'en_US.UTF-8' yerel ayarında' '\ x01 \ x01 \ x01 \ x01 Ւ '' döndürür. – jfs

+1

['icu.Collator.createInstance (icu.Locale ('en_US')) kullanabilirsiniz. GetSortKey' yerine] (http://stackoverflow.com/a/32178778/4279) – jfs

+0

@JFSebastian Evet, kullandım PyICU ve orada bir sorun olmadığını onaylayın. Stdlib 'locale' modülünde bu davranış hakkında daha fazla endişeliydim ve eğer bu bir çeşit kullanıcı hatasıysa (yani yanlış bir şey yaptım) veya daha hararetli bir şey varsa. – SethMMorton

cevap

7

Python 3.x'te locale.strxfrm(s) işlevi, geçerli LC_COLLATE ayarına dayalı olan wcsxfrm() POSIX C işlevini dahili olarak kullanır. POSIX standardı bu şekilde dönüşümü tanımlayın:

The transformation shall be such that if wcscmp() is applied to two transformed wide strings, it shall return a value greater than, equal to, or less than 0, corresponding to the result of wcscoll() applied to the same two original wide-character strings.

Bu tanım

çeşitli şekillerde uygulanabilir ve hatta Sonuç dizesi okunabilir olmasını gerektirmez.

nasıl çalıştığını göstermek için küçük bir C kodu örneği oluşturduk:

#include <stdio.h> 
#include <wchar.h> 
#include <locale.h> 

int main() { 
    wchar_t buf[10]; 
    wchar_t *in = L"\x10fefd"; 
    int i; 

    setlocale(LC_COLLATE, "en_US.UTF-8"); 

    printf("in : "); 
    for(i=0;i<10 && in[i];i++) 
    printf(" 0x%x", in[i]); 
    printf("\n"); 

    i = wcsxfrm(buf, in, 10); 

    printf("out: "); 
    for(i=0;i<10 && buf[i];i++) 
    printf(" 0x%x", buf[i]); 
    printf("\n"); 
} 

Daha önce ve dönüşüm sonrası dize yazdırır.

in : 0x10fefd 
out: 0x1 0x1 0x1 0x1 0x552 

OSX üzerinde çalışırken (10.11.1) sonucudur: Linux'ta Running

(Debian Jessie) bu sonucudur

in : 0x10fefd 
out: 0x103 0x1 0x110000 

Bunu görebilirsiniz OSX'de wcsxfrm() çıktısı, bir Python dizesinde izin verilmeyen U + 110000 karakterini içerir, dolayısıyla bu, hatanın kaynağıdır.

Python 2.7'de, locale.strxfrm() uygulaması strxfrm() C işlevine bağlı olduğundan hata yükseltilmez.

GÜNCELLEME:

ayrıca soruşturma, en_US.UTF-8 OSX'te için LC_COLLATE tanımı la_LN.US ASCII tanımına bir bağlantı olduğunu görüyoruz.

$ ls -l /usr/share/locale/en_US.UTF-8/LC_COLLATE 
lrwxr-xr-x 1 root wheel 28 Oct 1 14:24 /usr/share/locale/en_US.UTF-8/LC_COLLATE -> ../la_LN.US-ASCII/LC_COLLATE 

Ben Apple sources gerçek tanımını buldum.

order \ 
    \x00;...;\xff 

2 UPDATE: dosyanın la_LN.US-ASCII.src içeriği şudur

ben daha OSX'te wcsxfrm() fonksiyonunu test ettik. Bu algoritma \x10fefd kullanılarak

W1..Wn \x01 U1..Un 

Wx = 0x103 if Cx > 0xFF else Cx+0x3 
Ux = Cx+0x103 if Cx > 0xFF else Cx+0x3 

0x103 0x1 0x110000

hale gelir: geniş karakter C1..Cn bir dizi giriş olarak verilen la_LN.US ASCII harmanlama kullanılarak, çıkış bu formu ile birlikte, bir dizge

Her UTF-8 yerel ayarını kontrol ettim ve bu harmanlamayı OSX'de kullanıyorum, bu yüzden Apple sistemlerinde UTF-8 için harmanlama desteğinin bozuk olduğunu söylemeye meyilliyim. Ortaya çıkan sıralama, normal bayt karşılaştırmasıyla elde edilenle neredeyse aynıdır ve yasadışı Unicode karakterleri edinme yeteneği ile birlikte.

+0

Huh. Öyle görünüyor ki, “ValueError” ı önlemek için yapabileceğim pek bir şey yok çünkü bu, Python'un kontrolünün dışındaki C kütüphanesinden geliyor. – SethMMorton

+0

Bu bir hata olarak kabul edilir mi merak ediyorum. '0x110000'' wcsxfrm() 'için geçerli bir dönüş değeri olduğunu varsayarsak Python dahili olarak bunu halledebilir, doğru mu? Ancak, 0x110000'ün geçerli olmaması durumunda, Python’un yaptığı şeyin "doğru" olduğunu varsayalım. – SethMMorton

+0

Bu, 4 yıl önce ortaya çıkmış gibi görünüyor: https://mail.python.org/pipermail/python-dev/2011-December/114759.html ve http://bugs.python.org/issue13441. Gözlerimden, '= 0x110000' değerlerinin hatalarına bir çözüm bulmuş gibi görünmüyorlar, ancak fikir birliği kesinlikle onları istemiyorlardı. – SethMMorton