Conversión automática del formateador de cadenas avanzado del estilo antiguo

¿Hay alguna forma automática de convertir un fragmento de código del formato de cadena de estilo antiguo de python (usando % ) al nuevo estilo (usando .format )? Por ejemplo, considere el formato de una especificación de un átomo de PDB :

 spec = "%-6s%5d %4s%1s%3s %1s%4d%1s %8.3f%8.3f%8.3f%6.2f%6.2f %2s%2s" 

He estado convirtiendo algunas de estas especificaciones a mano según sea necesario, pero esto es tanto propenso a errores como lento, ya que tengo muchas de esas especificaciones.

La funcionalidad de los dos formularios no coincide exactamente, por lo que no hay forma de que pueda traducir automáticamente cada % cadena en una cadena {} equivalente o (especialmente) viceversa.

Por supuesto, hay mucha superposición, y muchas de las subpartes de los dos lenguajes de formato son iguales o muy similares, por lo que alguien podría escribir un convertidor parcial (que podría, por ejemplo, generar una excepción para el código no convertible) .

Para un pequeño subconjunto del lenguaje como lo que parece estar usando, puede hacerlo de forma bastante trivial con una expresión regular simple: cada patrón comienza con % y termina con uno de [sdf] , y algo como {:\1\2} Como patrón de reemplazo debe ser todo lo que necesitas.

Pero ¿por qué molestarse? Excepto como un ejercicio de escritura de analizadores, ¿cuál sería el beneficio? El operador % no está en desuso, y el uso de % con una cadena de formato % existente obviamente será al menos tan bueno como el format con una cadena de formato % convertida en {} .

Si está viendo esto como un ejercicio para escribir analizadores, creo que hay un ejemplo incompleto enterrado dentro de los parámetros .


Algunas diferencias que son difíciles de traducir, fuera de mi cabeza:

  • * para ancho de campo dynamic o precisión; format tiene una característica similar, pero lo hace de manera diferente.
  • %(10)s , porque el format intenta interpretar primero el nombre de la clave como un número, luego vuelve a una clave de dictado.
  • %(a[b])s , porque el format no cita ni separa la clave del rest del campo, por lo que simplemente no se puede usar una variedad de caracteres.
  • %c toma enteros o cadenas de un solo carácter; :c solo enteros.
  • %r análogos %r / %s / %a no son parte de la cadena de formato, sino una parte separada del campo (que también viene en el lado opuesto).
  • %g y :g tienen reglas de corte ligeramente diferentes.
  • %a y !a no hacen exactamente lo mismo.

Las diferencias reales no están listadas en ninguna parte; tendrá que desenterrarlos con una lectura minuciosa del Mini-Idioma de Especificación de Formato frente al lenguaje de Formato de Cadena de estilo printf .

Los documentos explican algunas de las diferencias. Por lo que puedo decir, aunque no estoy muy familiarizado con las cadenas de formato de estilo antiguo, es que la funcionalidad del nuevo estilo es un superconjunto de la funcionalidad del estilo antiguo.

Tendría que hacer más ajustes para manejar los casos de borde, pero creo que algo simple como

 re.replace(r'%(\w+)([sbcdoXnf...])', r'{\1\2}', your_string) 

Te conseguiría el 90% del camino. La traducción restante, que va de cosas como %x a {0:x} , será demasiado compleja para que la maneje una expresión regular (sin escribir algunos condicionales ridículamente complejos dentro de su expresión regular).