Получить STR repr с двойными кавычками Python

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

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

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

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

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

Я думаю, что просто replace('"', '"') может сделать работу, но, может, есть более подходящие для Python решение.

дополнительно:

было бы удобно также разделить данные в строках приблизительно 80 символов, но снова простой подход разделение исходной строки на куски размера 80 не будет работать, так как каждый непечатаемый символ занимает 2 или 3 символа в escape-последовательности. Разбиение списка на куски по 80 после получение repr также не поможет, так как он может разделить escape-последовательность.

какие предложения?

4 ответов


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

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

Если unicode=True, он выводит L" широкую " строку, которая может хранить 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""")

лучше не рубить repr() но использовать кодировку с самого начала. Вы можете получить кодировку repr непосредственно с помощью encoding 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\""

если вы спрашиваете 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')

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


можно попробовать json.dumps:

>>> import json
>>> print(json.dumps("hello world"))
"hello world"

>>> print(json.dumps('hëllo "world"!'))
"h\u00ebllo \"world\"!"

Я не знаю точно, совместимы ли строки json с C, но, по крайней мере, они имеют довольно большое общее подмножество и гарантированно совместимы с javascript;).