【问题标题】:Fast string array - Cython快速字符串数组 - Cython
【发布时间】:2013-07-04 21:08:04
【问题描述】:

假设代码如下:

cdef extern from "string.h":
    int strcmp(char* str1, char* str2)

def foo(list_str1, list_str2):
    cdef unsigned int i, j
    c_arr1 = ??
    c_arr2 = ??
    for i in xrange(len(list_str1)):
        for j in xrange(len(list_str2)):
            if not strcmp(c_arr1[i], c_arr2[j]):
                do some funny stuff

有没有办法将列表转换为 c 数组?

我已阅读并尝试过Cython - converting list of strings to char **,但这只会引发错误。

【问题讨论】:

  • 最近添加了类似任务的Python 3 solution here,也许你有兴趣阅读。

标签: python arrays string cython python-2.x


【解决方案1】:

试试下面的代码。以下代码中的to_cstring_array函数就是你想要的。

from libc.stdlib cimport malloc, free
from libc.string cimport strcmp
from cpython.string cimport PyString_AsString

cdef char ** to_cstring_array(list_str):
    cdef char **ret = <char **>malloc(len(list_str) * sizeof(char *))
    for i in xrange(len(list_str)):
        ret[i] = PyString_AsString(list_str[i])
    return ret

def foo(list_str1, list_str2):
    cdef unsigned int i, j
    cdef char **c_arr1 = to_cstring_array(list_str1)
    cdef char **c_arr2 = to_cstring_array(list_str2)

    for i in xrange(len(list_str1)):
        for j in xrange(len(list_str2)):
            if i != j and strcmp(c_arr1[i], c_arr2[j]) == 0:
                print i, j, list_str1[i]
    free(c_arr1)
    free(c_arr2)

foo(['hello', 'python', 'world'], ['python', 'rules'])

【讨论】:

  • PyString_AsString 仅适用于 python2,因此此解决方案不适用于 python3
  • @ead,除了PyString_AsString,OP 的代码中还有xrange 调用。所以我认为可以假设它是 python 2 代码。欢迎提出任何使该解决方案在 python 2/3 中都可以工作的建议。
  • 我发现在 Py3 中应该使用 PyUnicode_AsUTF8,但我遇到了错误:存储临时 Python 引用的不安全 C 派生。当我分解将 PyUnicode_AsUTF8(list_str[i]) 分配给临时变量的代码时,我遇到了另一个错误:'PyUnicode_AsUTF8' 不是常量、变量或函数标识符。我现在不知道如何进行。
  • 值得明确的是,存储的char* 的内存归 Python 字符串所有,因此仅在 Python 字符串仍然存在时才有效。这个问题很好,但我是从一个链接的问题来的,该问题复制了代码并遇到了问题
【解决方案2】:

如果您使用的是 Python 3,这里是 @falsetru 答案的更新(未经 Python 2 测试)。

cdef extern from "Python.h":
    char* PyUnicode_AsUTF8(object unicode)

from libc.stdlib cimport malloc, free
from libc.string cimport strcmp

cdef char ** to_cstring_array(list_str):
    cdef char **ret = <char **>malloc(len(list_str) * sizeof(char *))
    for i in xrange(len(list_str)):
        ret[i] = PyUnicode_AsUTF8(list_str[i])
    return ret

def foo(list_str1, list_str2):
    cdef unsigned int i, j
    cdef char **c_arr1 = to_cstring_array(list_str1)
    cdef char **c_arr2 = to_cstring_array(list_str2)

    for i in range(len(list_str1)):
        for j in range(len(list_str2)):
            if i != j and strcmp(c_arr1[i], c_arr2[j]) == 0:
                print(i, j, list_str1[i])
    free(c_arr1)
    free(c_arr2)

foo(['hello', 'python', 'world'], ['python', 'rules'])

警告:PyUnicode_AsUTF8 返回的指针被缓存在父 unicode-object 中。这有两个后果:

  1. 此指针仅在父 unicode 对象存在时才有效。之后访问它会导致未定义的行为(例如可能的分段错误)。
  2. PyUnicode_AsUTF8 的调用者负责释放内存。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-04
  • 2021-03-08
相关资源
最近更新 更多