Cadena de sustituciones mediante el uso de plantillas en Python

Introducción

La cadena módulo dispone de una Plantilla de clase, que le permite realizar sustituciones en una cadena mediante un objeto de asignación, por ejemplo:

>>> string.Template('var is $var').substitute({'var': 1})
'var is 1'

El método de sustitución puede plantear una KeyError excepción, si se realiza un intento de sustituir un elemento que falta en la asignación, por ejemplo

>>> string.Template('var is $var and foo is $foo').substitute({'var': 1})
KeyError: 'foo'

o pueden provocar un ValueError, si la plantilla de la cadena no es válida, por ejemplo, contiene un $ carácter seguido por un espacio:

>>> string.Template('$ var is $var').substitute({'var': 1})
ValueError: Invalid placeholder in string: line 1, col 1

El Problema

Dada una cadena de plantilla y una asignación, quiero para determinar si todos los titulares en la plantilla debería ser sustituido. Para ello, me gustaría tratar de hacer la sustitución y la captura de cualquier KeyError excepción:

def check_substitution(template, mapping):
    try:
        string.Template(template).substitute(mapping)
    except KeyError:
        return False
    except ValueError:
        pass
    return True

Pero esto no funciona, porque si la plantilla no es válida y un ValueError es elevado, posterior KeyErrors no son capturados:

>>> check_substitution('var is $var and foo is $foo', {'var': 1})
False
>>> check_substitution('$ var is $var and foo is $foo', {'var': 1})
True

pero me no importa sobre ValueErrors. Así que, ¿cuál sería el enfoque correcto para este problema?

Las plantillas tienen un safe_substitute método que ignora cualquier ValueError y va a hacer las sustituciones. El problema es que también se ignora KeyErrors.
La posible ValueError casos son todos los relacionados con los usos ilegales de la $ carácter, ¿verdad? Así que ¿por qué no hacer un poco de preprocesamiento de la cadena para escapar de los usos ilegales de $?
Esto podría funcionar, pero que habría que averiguar todos los casos que desencadenan una ValueError.

OriginalEl autor Ernest A | 2012-10-07

3 respuestas

  1. 5

    Los médicos dicen que puede reemplazar el patrón de tiempo que contiene todos los grupos con nombre:

    Pruebas

    f = check_substitution
    assert f('var is $var', var=1)
    assert f('$ var is $var', var=1)
    assert     f('var is $var and foo is $foo', var=1, foo=2)
    assert not f('var is $var and foo is $foo', var=1)
    assert     f('$ var is $var and foo is $foo', var=1, foo=2)
    assert not f('$ var is $var and foo is $foo', var=1)
    # support all invalid patterns
    assert f('var is $var and foo is ${foo', var=1)
    assert f('var is $var and foo is ${foo', var=1, foo=2) #NOTE: problematic API
    assert     f('var is $var and foo is ${foo and ${baz}', var=1, baz=3)
    assert not f('var is $var and foo is ${foo and ${baz}', var=1)

    Funciona para todos válidos ocurrencias de el delimitador ($).

    Los ejemplos muestran que ignorar los patrones no válidos oculta simples erratas en la plantilla por lo que no es una buena API.

    Perfecto! Voy a tener que pensar acerca de lo que usted dice que es una mala idea para apoyar patrones no válidos. Gracias.

    OriginalEl autor jfs

  2. 3

    Esta es una solución Rápida (Usando recursividad):

    def check_substitution(tem, m):
    try:
    string.Template(tem).substitute(m)
    except KeyError:
    return False
    except ValueError:
    return check_substitution(tem.replace('$ ', '$'), m) #strip spaces after $
    return True

    Sé que es tomar un largo tiempo si hay más de Un Espacio entre $ y var , así que usted puede mejorar mediante el uso de la Expresión Regular.

    EDITAR

    escapar $ en $$ tiene más sentido [ Gracias @Pedro ] así que usted puede coger ValueError por esta declaración:

    return check_substitution(tem.replace('$ ', '$$ '), m) #escaping $ by $$
    Esta solución no es genérico. Aun así no funciona si el personaje después de que el espacio no es una carta y se supone que el espacio después de la $ es falso y que la intención original era un marcador de posición compuesta de la $ y la palabra después de que el espacio. Escapando de la solitaria $ doblando tendría más sentido.
    Gracias, voy a editar mi respuesta.
    Gracias. El escape requeriría más trabajo, sin embargo. Por ejemplo, la plantilla de ${foo también provoca una ValueError, debido a la desequilibrada {… es por eso que yo quería evitar el análisis de la plantilla de mí, pero tal vez no hay alternativa.
    mi respuesta corrige ${foo problema.

    OriginalEl autor MBarsi

  3. -1

    Python no va a hacer la cadena de sustitución a través de varias líneas

    Si usted tiene esta cadena

    criterion = """
    <criteria>
    <order>{order}</order>
    <body><![CDATA[{code}]]></body>
    </criteria>
    """
    criterion.format(dict(order="1",code="Hello")

    resultados en:

    KeyError: 'order'

    Una solución es el uso de la cadena.Plantilla de módulo

    from string import Template
    criterion = """
    <criteria>
    <order>$order</order>
    <body><![CDATA[$code]]></body>
    </criteria>
    """
    Template(criterion).substitute(dict(order="1",code="hello")

    NOTA: usted tiene el prefijo de las palabras clave con una $ no envuelva en {}

    la salida es:

     <criteria>
    <order>1</order>
    <body><![CDATA[hello]]></body>
    </criteria>

    Completo docs son: https://docs.python.org/2/library/string.html#template-strings

    “Python no va a hacer la cadena de sustitución a través de varias líneas” – Falso. Uso criterion.format(**dict(order="1", code="Hello") o simplemente criterion.format(order="1", code="Hello")

    OriginalEl autor knowingpark

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *