Получить str-ревью с двойными кавычками Python

Я использую небольшой Python script для генерации некоторых двоичных данных, которые будут использоваться в заголовке C.

Эти данные должны быть объявлены как char[], и будет хорошо, если бы он мог быть закодирован как строка (с соответствующими управляющими последовательностями, когда они не находятся в диапазоне символов ASCII для печати), чтобы сохранить заголовок более компактный, чем с кодировкой десятичного или шестнадцатеричного массивов.

Проблема заключается в том, что когда я печатаю строку repr строки Python, она ограничивается одинарными кавычками, а C не нравится. Наивное решение состоит в том, чтобы сделать:

'"%s"'%repr(data)[1:-1]

но это не сработает, если один из байтов данных является двойной кавычкой, поэтому мне также понадобится их экранирование.

Я думаю, что простая replace('"', '\\"') могла бы выполнить эту работу, но, возможно, там было лучшее, более питоническое решение.

Дополнительная точка:

Было бы удобно также разделить данные в строках примерно на 80 символов, но опять же простой подход расщепления исходной строки в кусках размером 80 выиграл ' t, так как каждый непечатаемый символ принимает 2 или 3 символа в escape-последовательности. Разделение списка в кусках 80 после получения рефера также не поможет, поскольку оно может разделить escape-последовательность.

Любые предложения?

Ответ 1

repr() не то, что вы хотите. Существует фундаментальная проблема: repr() может использовать любое представление строки, которое может быть оценено как Python для создания строки. Это означает, что теоретически, что он может решить использовать любое количество других конструкций, которые не были бы действительны в C, такие как "" длинные строки "" ".

Этот код, вероятно, в правильном направлении. Я использовал стандартную упаковку на 140, что является разумным значением в 2009 году, но если вы действительно хотите, чтобы ваш код был равен 80 столбцам, просто измените его.

Если unicode = True, он выводит строку L "wide", которая может успешно хранить экраны Unicode. Кроме того, вам может потребоваться преобразовать символы Unicode в UTF-8 и вывести их с экранированием в зависимости от используемой вами программы.

def string_to_c(s, max_length = 140, unicode=False):
    ret = []

    # Try to split on whitespace, not in the middle of a word.
    split_at_space_pos = max_length - 10
    if split_at_space_pos < 10:
        split_at_space_pos = None

    position = 0
    if unicode:
        position += 1
        ret.append('L')

    ret.append('"')
    position += 1
    for c in s:
        newline = False
        if c == "\n":
            to_add = "\\\n"
            newline = True
        elif ord(c) < 32 or 0x80 <= ord(c) <= 0xff:
            to_add = "\\x%02x" % ord(c)
        elif ord(c) > 0xff:
            if not unicode:
                raise ValueError, "string contains unicode character but unicode=False"
            to_add = "\\u%04x" % ord(c)
        elif "\\\"".find(c) != -1:
            to_add = "\\%c" % c
        else:
            to_add = c

        ret.append(to_add)
        position += len(to_add)
        if newline:
            position = 0

        if split_at_space_pos is not None and position >= split_at_space_pos and " \t".find(c) != -1:
            ret.append("\\\n")
            position = 0
        elif position >= max_length:
            ret.append("\\\n")
            position = 0

    ret.append('"')

    return "".join(ret)

print string_to_c("testing testing testing testing testing testing testing testing testing testing testing testing testing testing testing testing testing", max_length = 20)
print string_to_c("Escapes: \"quote\" \\backslash\\ \x00 \x1f testing \x80 \xff")
print string_to_c(u"Unicode: \u1234", unicode=True)
print string_to_c("""New
lines""")

Ответ 2

Лучше не взламывать repr(), а использовать правую кодировку с самого начала. Вы можете получить кодировку спреда непосредственно с кодировкой string_escape

>>> "naïveté".encode("string_escape")
'na\\xc3\\xafvet\\xc3\\xa9'
>>> print _
na\xc3\xafvet\xc3\xa9

Для экранирования "-кодов, которые я думаю, используя простую замену после escape-кодирования, строка является абсолютно недвусмысленным процессом:

>>> '"%s"' % 'data:\x00\x01 "like this"'.encode("string_escape").replace('"', r'\"')
'"data:\\x00\\x01 \\"like this\\""'
>>> print _
"data:\x00\x01 \"like this\""

Ответ 3

Если вы запрашиваете python str для своего repr, я не думаю, что тип цитаты действительно настраивается. Из функции PyString_Repr в исходном дереве python 2.6.4:

    /* figure out which quote to use; single is preferred */
    quote = '\'';
    if (smartquotes &&
        memchr(op->ob_sval, '\'', Py_SIZE(op)) &&
        !memchr(op->ob_sval, '"', Py_SIZE(op)))
        quote = '"';

Итак, я предполагаю использовать двойные кавычки, если в строке есть одна цитата, но даже не тогда, если в строке есть двойная кавычка.

Я бы попробовал что-то вроде написания собственного класса, чтобы содержать строковые данные вместо того, чтобы использовать встроенную строку для этого. Один из вариантов - вывести класс из str и записать собственный repr:

class MyString(str):
    __slots__ = []
    def __repr__(self):
        return '"%s"' % self.replace('"', r'\"')

print repr(MyString(r'foo"bar'))

Или, не используйте repr вообще:

def ready_string(string):
    return '"%s"' % string.replace('"', r'\"')

print ready_string(r'foo"bar')

Это упрощенное цитирование может не выполнять "правильную" вещь, если в строке уже есть скрытая цитата.