2012-06-20 14 views
7

Farklı dillerden metinler kullanan bir uygulama üzerinde çalışıyorum, dolayısıyla görüntüleme veya raporlama amacıyla bazı metinlerin (dizeler) belirli bir dilde sıralanması gerekir.Python'da belirli yerel ayarlı dizgenin listesi

Şu anda kötü küresel yerel ayarlarına, karıştırmasını bir çözüm var ve üretimde koymak istemiyorum:

default_locale = locale.getlocale(locale.LC_COLLATE) 

def sort_strings(strings, locale_=None): 
    if locale_ is None: 
     return sorted(strings) 

    locale.setlocale(locale.LC_COLLATE, locale_) 
    sorted_strings = sorted(strings, cmp=locale.strcoll) 
    locale.setlocale(locale.LC_COLLATE, default_locale) 

    return sorted_strings 

resmi piton yerel belgeleri açıkça tasarrufu ve geri yükleme söylüyor kötü bir fikir olduğunu, ancak herhangi bir öneri vermez: http://docs.python.org/library/locale.html#background-details-hints-tips-and-caveats

cevap

3

Glibc açık bir duruma sahip bir yerel API destekler. İşte bu API için klişeler ile yapılan hızlı bir sarmalayıcı.

# -*- coding: utf-8 
import ctypes 


class Locale(object): 
    def __init__(self, locale): 
     LC_ALL_MASK = 8127 
     # LC_COLLATE_MASK = 8 
     self.libc = ctypes.CDLL("libc.so.6") 
     self.ctx = self.libc.newlocale(LC_ALL_MASK, locale, 0) 



    def strxfrm(self, src, iteration=1): 
     size = 3 * iteration * len(src) 
     dest = ctypes.create_string_buffer('\000' * size) 
     n = self.libc.strxfrm_l(dest, src, size, self.ctx) 
     if n < size: 
      return dest.value 
     elif iteration<=4: 
      return self.strxfrm(src, iteration+1) 
     else: 
      raise Exception('max number of iterations trying to increase dest reached') 


    def __del__(self): 
     self.libc.freelocale(self.ctx) 

ve yapılacak kalanları

locale1 = Locale('C') 
locale2 = Locale('mk_MK.UTF-8') 

a_list = ['а', 'б', 'в', 'ј', 'ќ', 'џ', 'ш'] 
import random 
random.shuffle(a_list) 

assert sorted(a_list, key=locale1.strxfrm) == ['а', 'б', 'в', 'ш', 'ј', 'ќ', 'џ'] 
assert sorted(a_list, key=locale2.strxfrm) == ['а', 'б', 'в', 'ј', 'ќ', 'џ', 'ш'] 

(* fonksiyonlar sanırım wchar ile) piton unicode dizeleri tüm yerel işlevlerini, desteğe uygulamak kısa bir testi ve otomatik içe dosya tanımlarını kapsar falan

2

Global ayarları değiştirerek önlemek için PyICU 'ın burster kullanabilirsiniz:

import icu # PyICU 

def sorted_strings(strings, locale=None): 
    if locale is None: 
     return sorted(strings) 
    collator = icu.Collator.createInstance(icu.Locale(locale)) 
    return sorted(strings, key=collator.getSortKey) 

Örnek:

>>> L = [u'sandwiches', u'angel delight', u'custard', u'éclairs', u'glühwein'] 
>>> sorted_strings(L) 
['angel delight', 'custard', 'glühwein', 'sandwiches', 'éclairs'] 
>>> sorted_strings(L, 'en_US') 
['angel delight', 'custard', 'éclairs', 'glühwein', 'sandwiches'] 

Dezavantajı: PyICU library üzerine bağımlılığının; davranış locale.strcoll'dan biraz farklıdır.


Ben küresel onu değiştirmeden bir yerel ismi verilen locale.strxfrm fonksiyonunu nasıl bilmiyorum. Bir olarak, farklı bir alt sürecin Işlevinizin çalıştırabilir kesmek:

pool = multiprocessing.Pool() 
# ... 
pool.apply(locale_aware_sort, [strings, loc]) 

Dezavantajı: Kullanılması


yavaş olabilir, kaynak sıradan sürece çalışmayacaktır threading.Lock Yerel ayar fonksiyonlarının (locale modülü, örneğin re ile sınırlı değildir) her yerde birden fazla ileti dizisinden çağrılabilir.


Gil kullanarak erişimi eşitlemek için Cython kullanarak işlevini derlemek olabilir. GIL, işleviniz çalışırken başka bir Python kodunun yürütülmemesini sağlar.

Dezavantajı: değil saf Python

2

ctypes çözüm iyi, ama ileride herkesin sadece orijinal çözüm değiştirmek istiyorsanız, buraya Bunun nasıl bir yoludur:

Genel ayarların geçici olarak değiştirilebilmesi, içerik yöneticisi ile güvenli bir şekilde gerçekleştirilebilir.

Bu, iş parçacığı kullanmadığınız sürece orijinal yerel ayarın temiz bir şekilde geri yüklenmesini sağlar.

İlgili konular