Сортировка списка строк с определенной локалью в python

Я работаю над приложением, которое использует тексты с разных языков, поэтому для просмотра или создания отчетов некоторые тексты (строки) необходимо сортировать на определенном языке.

В настоящее время у меня есть обходное взаимодействие с глобальными настройками локали, что плохо, и я не хочу его выпускать:

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 

Официальная документация на языке python явно говорит о том, что сохранение и восстановление – плохая идея, но не дает никаких предложений: http://docs.python.org/library/locale.html#background-details-hints-tips-and-caveats

  • Иерархическая кластеризация 1 миллиона объектов
  • построить динамический запрос SQL с помощью библиотеки python psycopg2 и использовать хорошие инструменты для преобразования типов
  • Метки / названия Matplotlib исчезают при экспорте в формате eps
  • Python 3 против поведения карты Python 2
  • Разархивировать zip-файлы в папки и подпапки с помощью python
  • Основной запрос относительно bindtags в tkinter
  • Вложенная перекрестная проверка в сетке поиска предварительно вычисленных ядер в scikit-learn
  • Python NameError: имя не определено
  • 3 Solutions collect form web for “Сортировка списка строк с определенной локалью в python”

    Glibc поддерживает API локали с явным состоянием. Вот быстрая оболочка для этого API, созданная с помощью ctypes.

     # -*- 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) 

    и короткий тест

     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) == ['а', 'б', 'в', 'ј', 'ќ', 'џ', 'ш'] 

    что нужно сделать, это реализовать все языковые функции, поддерживать строки unicode python (с функциями wchar *, которые, как я полагаю), и автоматически импортировать описания файлов include или что-то еще

    Вы можете использовать коллайдер PyICU , чтобы избежать изменения глобальных настроек:

     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) 

    Пример:

     >>> 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'] 

    Недостаток: зависимость от библиотеки ПИКЮ ; поведение немного отличается от locale.strcoll .


    Я не знаю, как получить функцию locale.strxfrm учитывая имя локали, не изменяя ее глобально. В качестве взлома вы можете запустить свою функцию в другом дочернем процессе :

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

    Недостаток: может быть медленным, ресурс голоден


    Использование обычной threading.Lock не будет работать, если вы не сможете контролировать все места, где функции локального распознавания (они не ограничены locale модулем, например, re ) могут быть вызваны из нескольких потоков.


    Вы можете скомпилировать свою функцию с помощью Cython для синхронизации доступа с помощью GIL. GIL будет убедиться, что никакой другой код Python не будет выполнен во время работы вашей функции.

    Недостаток: не чистый Python

    Решение ctypes прекрасное, но если кто-то в будущем хотел бы просто изменить ваше оригинальное решение, вот как это сделать:

    Временные изменения глобальных параметров можно безопасно выполнить с помощью менеджера контекста.

     from contextlib import contextmanager import locale @contextmanager def changedlocale(newone): old_locale = locale.getlocale(locale.LC_COLLATE) try: locale.setlocale(locale.LC_COLLATE, newone) yield locale.strcoll finally: locale.setlocale(locale.LC_COLLATE, old_locale) def sort_strings(strings, locale_=None): if locale_ is None: return sorted(strings) with changedlocale(locale_) as strcoll: return sorted(strings, cmp=strcoll) return sorted_strings 

    Это обеспечивает чистое восстановление исходного языка – если вы не используете резьбу.

    Python - лучший язык программирования в мире.