C массив символов из python строки - PullRequest
0 голосов
/ 16 июня 2020

У меня есть список строк в python, который я пытаюсь передать расширению C для анализа символов. Я дошел до того, что разбил список на отдельные строки PyObjects. Затем я надеюсь разделить эти строки на отдельные символы, чтобы каждая строка PyObject теперь представляла собой соответствующий массив символов типа C. Я не могу понять, как это сделать. все остальное работает), я просто не знаю, как разбить строку 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,
)

1 Ответ

1 голос
/ 16 июня 2020

Вы можете использовать PyUnicode_AsEncodedString, который

кодирует объект Unicode и возвращает результат как Python байтовый объект. кодировка и ошибки имеют то же значение, что и одноименные параметры в методе Unicode encode (). Используемый код c ищется с помощью реестра Python code c. Вернуть NULL, если исключение было вызвано кодом c.

см. 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).

...