我目前正在从事一个宠物项目。我现在的目标是用 cython 为 python 编写一个 c++ 类的包装器。问题是我必须使用俄语文本 (unicode),但是 cython 包装只需要字节,尽管有 c++ 类方法,它能够正确处理 unicode 字符串。我阅读了 Cython 文档并试图在谷歌中找到它,但一无所获。
我如何更改我的代码,以便我的 python 包装器可以采用 unicode 字符串?
这是我的 github 存储库的链接,其中包含当前的代码文件 https://github.com/rproskuryakov/lemmatizer/tree/trie
“trie.pxd”
from libcpp.string cimport string
from libcpp cimport bool
cdef extern from "Trie.cpp":
pass
# Declare the class with cdef
cdef extern from "Trie.h":
cdef cppclass Trie:
Trie() except +
void add_word(string word) # function that should take unicode
bool find(string word) # function that should take unicode
“pytrie.pyx”
from trie cimport Trie # link to according .pxd file
# Create a Cython extension type which holds a C++ instance
# as an attribute and create a bunch of forwarding methods
# Python extension type.
cdef class PyTrie:
cdef Trie c_tree # Hold a C++ instance which we're wrapping
def __cinit__(self):
self.c_tree = Trie()
def add_word(self, word):
return self.c_tree.add_word(word)
def find(self, word):
return self.c_tree.find(word)
这是我在 python 中得到的。
>>> tree.add_word(b'hello') # works if i got english into ascii
>>> tree.add_word(b'привет') # doesnt work
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "wrapper/pytrie.pyx", line 13, in pytrie.PyTrie.add_word
File "stringsource", line 15, in string.from_py.__pyx_convert_string_from_py_std__in_string
TypeError: expected bytes, str found
最佳答案
C++ 字符串在内部是一个 char
数组,因此实际上是在“字节”级别而不是 unicode 级别上运行。因此,Cython 不会自动支持 unicode/str
<-> std::string
转换。但是,您有两个相当简单的选择:
使用
unicode/str.encode
函数获取 unicode 对象的字节表示:def add_word(self, word): if isinstance(word,str): # Python3 version - use unicode for Python 2 word = word.encode() return self.c_tree.add_word(word)
您必须注意的主要事情是,C++ 用于解释它的编码与 Python 用于对其进行编码的编码相同(Python 默认使用 utf8)。
转换为 C++ 类型
std::wstring
- 内部是一个wchar_t
数组。不幸的是,Cython 默认不包装wstring
或提供自动转换,因此您需要编写自己的包装器。使用 Cython wrapping ofstd::string
作为引用——你可能只需要包装构造函数。我用过 the Python C API用于转换为wchar_t*
。from libc.stddef cimport wchar_t cdef extern from "<string>" namespace std: cdef cppclass wstring: wstring() except + wstring(size_t, wchar_t) except + const wchar_T* data() cdef extern from "Python.h": # again, not wrapped by cython a s adefault Py_ssize_t PyUnicode_AsWideChar(object o, wchar_t *w, Py_ssize_t size) except -1 # conversion function cdef wstring to_wstring(s): # create 0-filled output cdef wstring out = wstring(len(s),0) PyUnicode_AsWideChar(s, <wchar_t*>out.data(),len(s)) # note cast to remove const # I'm not convinced this is 100% acceptable according the standard but practically it should work return out
您更喜欢这些选项中的哪一个很大程度上取决于您的 C++ 接受的 unicode 字符串。
关于python - 如何在 python 包装中使用 unicode 字符串为 c++ 类使用 cython?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57401078/