开发者社区> 问答> 正文

不确定编码格式的C字符串

你要在C和Python直接来回转换字符串,但是C中的编码格式并不确定。 例如,可能C中的数据期望是UTF-8,但是并没有强制它必须是。 你想编写代码来以一种优雅的方式处理这些不合格数据,这样就不会让Python奔溃或者破坏进程中的字符串数据。

展开
收起
哦哦喔 2020-04-17 18:16:04 3027 0
1 条回答
写回答
取消 提交回答
  • 面是一些C的数据和一个函数来演示这个问题:
    
    /* Some dubious string data (malformed UTF-8) */
    const char *sdata = "Spicy Jalape\xc3\xb1o\xae";
    int slen = 16;
    
    /* Output character data */
    void print_chars(char *s, int len) {
      int n = 0;
      while (n < len) {
        printf("%2x ", (unsigned char) s[n]);
        n++;
      }
      printf("\n");
    }
    在这个代码中,字符串 sdata 包含了UTF-8和不合格数据。 不过,如果用户在C中调用 print_chars(sdata, slen) ,它缺能正常工作。 现在假设你想将 sdata 的内容转换为一个Python字符串。 进一步假设你在后面还想通过一个扩展将那个字符串传个 print_chars() 函数。 下面是一种用来保护原始数据的方法,就算它编码有问题。
    
    /* Return the C string back to Python */
    static PyObject *py_retstr(PyObject *self, PyObject *args) {
      if (!PyArg_ParseTuple(args, "")) {
        return NULL;
      }
      return PyUnicode_Decode(sdata, slen, "utf-8", "surrogateescape");
    }
    
    /* Wrapper for the print_chars() function */
    static PyObject *py_print_chars(PyObject *self, PyObject *args) {
      PyObject *obj, *bytes;
      char *s = 0;
      Py_ssize_t   len;
    
      if (!PyArg_ParseTuple(args, "U", &obj)) {
        return NULL;
      }
    
      if ((bytes = PyUnicode_AsEncodedString(obj,"utf-8","surrogateescape"))
            == NULL) {
        return NULL;
      }
      PyBytes_AsStringAndSize(bytes, &s, &len);
      print_chars(s, len);
      Py_DECREF(bytes);
      Py_RETURN_NONE;
    }
    如果你在Python中尝试这些函数,下面是运行效果:
    
    >>> s = retstr()
    >>> s
    'Spicy Jalapeño\udcae'
    >>> print_chars(s)
    53 70 69 63 79 20 4a 61 6c 61 70 65 c3 b1 6f ae
    >>>
    仔细观察结果你会发现,不合格字符串被编码到一个Python字符串中,并且并没有产生错误, 并且当它被回传给C的时候,被转换为和之前原始C字符串一样的字节。
    
    2020-04-17 18:16:13
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载