2009-11-04 47 views
11

Estoy usando una pequeña secuencia de comandos de Python para generar algunos datos binarios que se utilizarán en un encabezado C.Obtener str repr con comillas dobles Python

Estos datos debe ser declarada como char[], y que será bueno si pudiera ser codificada como una cadena (con las secuencias de escape pertinentes cuando no están en el rango de ASCII caracteres imprimibles) para mantener la cabecera más compacto que con una codificación de matriz decimal o hexadecimal.

El problema es que cuando imprimo el repr de una cadena de Python, está delimitado por comillas simples, y C no le gusta. La solución es hacer ingenua:

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

pero eso no funciona cuando uno de los bytes de los datos pasa a ser una cita doble, por lo que necesitaría que sean escaparon también.

Creo que un simple replace('"', '\\"') podría hacer el trabajo, pero tal vez hay una solución mejor, más pitonica por ahí.

punto extra:

Sería conveniente también para dividir los datos en líneas de aproximadamente 80 caracteres, pero de nuevo el enfoque simple de splitting the source string in chunks de tamaño 80 no funcionará, ya que cada carácter no imprimible toma 2 o 3 caracteres en la secuencia de escape. Dividir la lista en fragmentos de 80 después de obtener la repr tampoco ayudará, ya que podría dividir la secuencia de escape.

¿Alguna sugerencia?

Respuesta

4

repr() no es lo que quieres.Hay un problema fundamental: repr() puede usar cualquier representación de la cadena que se pueda evaluar como Python para producir la cadena. Eso significa que, en teoría, que podría decidir utilizar cualquier número de otras construcciones que no serían válidos en C, tales como "" "largas cadenas" "".

Este código es probablemente la dirección correcta. He usado un defecto de envolver a 140, que es un valor razonable para el 2009, pero si realmente quieres para envolver su código de 80 columnas, simplemente lo cambio.

Si Unicode = True, se da salida a una L "amplia" cadena, que puede almacenar Unicode escapa de manera significativa. Alternativamente, es posible que desee convertir caracteres Unicode UTF-8 y salida de ellos escaparon, dependiendo del programa que los está utilizando en.

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""") 
+0

no es el 'elif "\\\". "Encontrar (c)! = -1' lo mismo que 'elif c en "\\\""'? En cualquier caso, estoy de acuerdo, repr() no es la solución aquí y tienes que hacer algo como esto. –

+0

La recomendación del texto de 80 columnas no se basó en el ancho del monitor. Viene de la tipografía. Mire algunos periódicos: mire una publicación sensacionalista en una hoja ancha. ¿Qué tan anchas son las columnas? –

6

Mejor no piratear el repr(), pero use la codificación correcta desde el principio. Usted puede obtener la codificación de la repr directamente con la codificación string_escape

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

para escapar de la "-quotes creo que el uso de un reemplazo simple después de la fuga que codifica la cadena es un proceso completamente inequívoca:

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

que no resuelve mi problema, nos muestra comillas dobles sin escape ' 'quotehere "'. codificar ("string_escape")' 'da 'quotehere"' ' – fortran

+0

En Python 3 es [' unicode_escape'] (https://docs.python.org/3/library/codecs.html?highlight = unicode_escape # text-coddings). Ver también [esta respuesta para otra pregunta] (https://stackoverflow.com/a/6868026). –

6

Si que está pidiendo una pitón str por su repr, no creo que el tipo de cotización es muy configurable desde la función PyString_Repr en el árbol Python 2.6.4 fuente:.

/* 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 = '"'; 

Supongo que se utilizan comillas dobles si hay una comilla simple en la cadena, pero ni siquiera si hay una comilla doble en la cadena.

Me gustaría intentar algo así como escribir mi propia clase para contener los datos de cadena en lugar de utilizar la cadena incorporada para hacerlo. Una opción sería la derivación de una clase a partir de str y escribir su propio repr:

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

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

O, no utilizan en absoluto repr:

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

print ready_string(r'foo"bar') 

Esta simplista citando podría no hacer lo "correcto" si ya hay una cita escapada en la cadena.

+0

+1 ¡La extensión de str es una idea brillante! ¡Gracias! –

Cuestiones relacionadas