来自python字符串的C char数组
Posted
技术标签:
【中文标题】来自python字符串的C char数组【英文标题】:C char array from python string 【发布时间】:2020-10-06 07:56:03 【问题描述】:我在 python 中有一个字符串列表,我试图将其传递给 C 扩展以进行字符分析。到目前为止,我已经将列表分解为它们各自的字符串 PyObjects。接下来,我希望将这些字符串拆分为单独的字符,这样每个字符串 PyObject 现在都是一个对应的 C 类型字符数组。不过,我似乎无法弄清楚如何做到这一点。
这是我到目前为止所拥有的:目前在构建 .pyd 文件后,它将返回一个 1 的列表作为 Python 的填充符(因此其他一切都有效),我只是不知道如何将字符串 PyObject 拆分为C型字符数组。
--- cExt.c ---
#include <Python.h>
#include <stdio.h>
static int *CitemCheck(PyObject *commandString, int commandStringLength)
// HAALP
//char* commandChars = (char*) malloc(commandStringLength*sizeof(char*));
// char c[] = PyString_AsString("c", commandString);
// printf("%c" , c);
// printf("%s", PyString_AsString(commandString));
// for (int i=0; i<sizeof(commandChars)/sizeof(*commandChars); i++)
// printf("%s", PyString_AsString(commandString));
// printf("%c", commandChars[i]);
//
return 1; // TODO: RETURN PROPER RESULTANT
static PyObject *ClistCheck(PyObject *commandList, int commandListLength)
PyObject *results = PyList_New(commandListLength);
for (int index = 0; index < commandListLength; index++)
PyObject *commandString;
commandString = PyList_GetItem(commandList, index);
int commandStringLength = PyObject_Length(commandString);
// CitemCheck should take string PyObject and its length as int
int x = CitemCheck(commandString, commandStringLength);
PyObject* pyItem = Py_BuildValue("i", x);
PyList_SetItem(results, index, pyItem);
return results;
static PyObject *parseListCheck(PyObject *self, PyObject *args)
PyObject *commandList;
int commandListLength;
if (!PyArg_ParseTuple(args, "O", &commandList))
return NULL;
commandListLength = PyObject_Length(commandList);
return Py_BuildValue("O", ClistCheck(commandList, commandListLength));
static char listCheckDocs[] =
""; // TODO: ADD DOCSTRING
static PyMethodDef listCheck[] =
"listCheck", (PyCFunction) parseListCheck, METH_VARARGS, listCheckDocs,
NULL,NULL,0,NULL
;
static struct PyModuleDef DCE =
PyModuleDef_HEAD_INIT,
"listCheck",
NULL,
-1,
listCheck
;
PyMODINIT_FUNC PyInit_cExt(void)
return PyModule_Create(&DCE);
作为参考,我的临时扩展构建文件:
--- _c_setup.py ---
(located in same folder as cExt.c)
"""
to build C files, pass:
python _c_setup.py build_ext --inplace clean --all
in command prompt which is cd'd to the file's dierctory
"""
import glob
from setuptools import setup, Extension, find_packages
from os import path
here = path.abspath(path.dirname(__file__))
files = [path.split(x)[1] for x in glob.glob(path.join(here, '**.c'))]
extensions = [Extension(
path.splitext(x)[0], [x]
) for x in files]
setup(
ext_modules = extensions,
)
【问题讨论】:
请注意;我确信一个简单的解决方案是将字符串列表处理成 Python 级别的字符列表,但我宁愿尝试在 C 级别处理它。 【参考方案1】:您可以使用 PyUnicode_AsEncodedString,其中
编码一个 Unicode 对象并将结果作为 Python 字节对象返回。 encoding 和 errors 与 Unicode encode() 方法中的同名参数含义相同。使用 Python 编解码器注册表查找要使用的编解码器。如果编解码器引发异常,则返回 NULL。
见https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_AsEncodedString
然后使用 PyBytes_AsString 你会得到一个指向带有终止 NUL 字节的内部缓冲区的指针。这个缓冲区既不能被释放也不能被修改。如果您需要副本,可以使用例如strdup。
见https://docs.python.org/3/c-api/bytes.html#c.PyBytes_AsString
稍微修改一下你的代码,它可能看起来像这样:
PyObject *encodedString = PyUnicode_AsEncodedString(commandString, "UTF-8", "strict");
if (encodedString) //returns NULL if an exception was raised
char *commandChars = PyBytes_AsString(encodedString); //pointer refers to the internal buffer of encodedString
if(commandChars)
printf("the string '%s' consists of the following chars:\n", commandChars);
for (int i = 0; commandChars[i] != '\0'; i++)
printf("%c ", commandChars[i]);
printf("\n");
Py_DECREF(encodedString);
如果有人会测试:
import cExt
fruits = ["apple", "pears", "cherry", "pear", "blueberry", "strawberry"]
res = cExt.listCheck(fruits)
print(res)
输出将是:
the string 'apple' consists of the following chars:
a p p l e
the string 'pears' consists of the following chars:
p e a r s
the string 'cherry' consists of the following chars:
c h e r r y
the string 'pear' consists of the following chars:
p e a r
the string 'blueberry' consists of the following chars:
b l u e b e r r y
the string 'strawberry' consists of the following chars:
s t r a w b e r r y
[1, 1, 1, 1, 1, 1]
与问题没有直接关系的旁注: 您的 CitemCheck 函数返回一个指向 int 的指针,但如果查看它的调用方式,您似乎想要返回一个 int 值。函数签名应该看起来更像这样:
static int CitemCheck(PyObject *commandString, int commandStringLength)
(注意 int 后删除的*
)。
【讨论】:
以上是关于来自python字符串的C char数组的主要内容,如果未能解决你的问题,请参考以下文章
python ctypes中的多维char数组(字符串数组)
使用包含来自 Node.js 的 char 数组的结构调用 C++ dll