von*_*hev 9 python ctypes locale glibc
我在使用来自不同语言的文本的应用程序,因此,为了查看或报告目的,某些文本(字符串)需要以特定语言进行排序.
目前我有一个解决方法搞乱全局区域设置,这是不好的,我不想把它投入生产:
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
Run Code Online (Sandbox Code Playgroud)
官方python语言环境文档明确说明保存和恢复是一个坏主意,但没有给出任何建议:http://docs.python.org/library/locale.html#background-details-hints-tips-and-caveats
您可以使用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)
Run Code Online (Sandbox Code Playgroud)
例子:
>>> 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']
Run Code Online (Sandbox Code Playgroud)
缺点:依赖PyICU 库;行为与 略有不同locale.strcoll。
我不知道如何在locale.strxfrm不全局更改的情况下获取给定区域设置名称的函数。作为黑客,您可以在不同的子进程中运行您的函数:
pool = multiprocessing.Pool()
# ...
pool.apply(locale_aware_sort, [strings, loc])
Run Code Online (Sandbox Code Playgroud)
缺点:可能很慢,资源匮乏
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
Run Code Online (Sandbox Code Playgroud)
这确保了原始语言环境的干净恢复 - 只要您不使用线程。
Glibc 确实支持具有显式状态的语言环境 API。这是使用 ctypes 制作的 API 的快速包装器。
\n\n# -*- coding: utf-8\nimport ctypes\n\n\nclass Locale(object):\n def __init__(self, locale):\n LC_ALL_MASK = 8127\n # LC_COLLATE_MASK = 8\n self.libc = ctypes.CDLL("libc.so.6")\n self.ctx = self.libc.newlocale(LC_ALL_MASK, locale, 0)\n\n\n\n def strxfrm(self, src, iteration=1):\n size = 3 * iteration * len(src)\n dest = ctypes.create_string_buffer(\'\\000\' * size)\n n = self.libc.strxfrm_l(dest, src, size, self.ctx)\n if n < size:\n return dest.value\n elif iteration<=4:\n return self.strxfrm(src, iteration+1)\n else:\n raise Exception(\'max number of iterations trying to increase dest reached\')\n\n\n def __del__(self):\n self.libc.freelocale(self.ctx)\nRun Code Online (Sandbox Code Playgroud)\n\n和一个简短的测试
\n\nlocale1 = Locale(\'C\')\nlocale2 = Locale(\'mk_MK.UTF-8\')\n\na_list = [\'\xd0\xb0\', \'\xd0\xb1\', \'\xd0\xb2\', \'\xd1\x98\', \'\xd1\x9c\', \'\xd1\x9f\', \'\xd1\x88\']\nimport random\nrandom.shuffle(a_list)\n\nassert sorted(a_list, key=locale1.strxfrm) == [\'\xd0\xb0\', \'\xd0\xb1\', \'\xd0\xb2\', \'\xd1\x88\', \'\xd1\x98\', \'\xd1\x9c\', \'\xd1\x9f\']\nassert sorted(a_list, key=locale2.strxfrm) == [\'\xd0\xb0\', \'\xd0\xb1\', \'\xd0\xb2\', \'\xd1\x98\', \'\xd1\x9c\', \'\xd1\x9f\', \'\xd1\x88\']\nRun Code Online (Sandbox Code Playgroud)\n\n剩下要做的就是实现所有语言环境函数,支持 python unicode 字符串(我猜是 wchar* 函数),并自动导入包含文件定义或其他东西
\n| 归档时间: |
|
| 查看次数: |
4433 次 |
| 最近记录: |