multiple examples python string customization string-formatting

examples - python string format replace



Formato de cadena plural (4)

Dado un diccionario de int s, estoy tratando de formatear una cadena con cada número y una pluralización del elemento.

Ejemplo de entrada dict :

data = {''tree'': 1, ''bush'': 2, ''flower'': 3, ''cactus'': 0}

Salida de muestra:

''My garden has 1 tree, 2 bushes, 3 flowers, and 0 cacti''

Necesita trabajar con una cadena de formato arbitrario.

La mejor solución que he encontrado es una clase PluralItem para almacenar dos atributos, n (el valor original) y s (la cadena ''s'' si es plural, cadena vacía '''' si no). Subclasificado por diferentes métodos de pluralización.

class PluralItem(object): def __init__(self, num): self.n = num self._get_s() def _get_s(self): self.s = '''' if self.n == 1 else ''s'' class PluralES(PluralItem): def _get_s(self): self.s = ''s'' if self.n == 1 else ''es'' class PluralI(PluralItem): def _get_s(self): self.s = ''us'' if self.n == 1 else ''i''

Luego haga un nuevo dict través de la comprensión y un mapeo de classes :

classes = {''bush'': PluralES, ''cactus'': PluralI, None: PluralItem} plural_data = {key: classes.get(key, classes[None])(value) for key, value in data.items()}

Por último, la cadena de formato, y la implementación:

formatter = ''My garden has {tree.n} tree{tree.s}, {bush.n} bush{bush.s}, {flower.n} flower{flower.s}, and {cactus.n} cact{cactus.s}'' print(formatter.format(**plural_data))

Salidas de lo siguiente:

My garden has 1 tree, 2 bushes, 3 flowers, and 0 cacti

Para una necesidad tan común, indudablemente, vacilo en tirar la toalla con una solución tan complicada.

¿Hay alguna forma de formatear una cadena como esta usando el método de format incorporado y un código adicional mínimo? Pseudocódigo podría ser algo como:

"{tree} tree{tree(s)}, {bush} bush{bush(es)}, {flower} flower{flower(s)}, {cactus} cact{cactus(i,us)}".format(data)

donde los paréntesis devuelven el contenido si el valor es plural, o si el contenido tiene una coma, significa plural / singular


Echa un vistazo al paquete de inflexión . Pluralizará las cosas, así como una gran cantidad de otros trucos lingüísticos. ¡Hay demasiadas situaciones especiales para este caso!

De los documentos en el enlace de arriba:

import inflect p = inflect.engine() # UNCONDITIONALLY FORM THE PLURAL print("The plural of ", word, " is ", p.plural(word)) # CONDITIONALLY FORM THE PLURAL print("I saw", cat_count, p.plural("cat",cat_count))

Para su ejemplo específico:

{print(str(count) + " " + p.pluralize(string, count)) for string, count in data.items() }


Iría con algo como

class Pluralizer: def __init__(self, value): self.value = value def __format__(self, formatter): formatter = formatter.replace("N", str(self.value)) start, _, suffixes = formatter.partition("/") singular, _, plural = suffixes.rpartition("/") return "{}{}".format(start, singular if self.value == 1 else plural) "There are {:N thing/s} which are made of {:/a cactus/N cacti}".format(Pluralizer(10), Pluralizer(1)) #>>> ''There are 10 things which are made of a cactus''

El formato es always/singular/plural , cuyo singular (entonces plural ) es opcional.

Asi que

"xyz/foo/bar".format(Pluralizer(1)) == "xyzfoo" "xyz/foo/bar".format(Pluralizer(2)) == "xyzbar" "xyz/bar".format(Pluralizer(1)) == "xyz" "xyz/bar".format(Pluralizer(2)) == "xyzbar" "xyz".format(Pluralizer(1)) == "xyz" "xyz".format(Pluralizer(2)) == "xyz"

Entonces para tu ejemplo uno solo hace:

data = {''tree'': 1, ''bush'': 2, ''flower'': 3, ''cactus'': 0} string = ''My garden has {tree:N tree/s}, {bush:N bush/es}, {flower:N flower/s}, and {cactus:N cact/us/i}'' string.format_map({k: Pluralizer(v) for k, v in data.items()}) #>>> ''My garden has 1 tree, 2 bushes, 3 flowers, and 0 cacti''


Si ya usas Django, es fácil: pluralize es una función que.

Se utiliza a menudo en plantillas:

You have {{ num_messages }} message{{ num_messages|pluralize }}.

Sin embargo, también puedes usarlo en tu código de python:

f''You have {num_messages} message{pluralize(num_messages)}.''

En Python2 esto leería:

''You have {} message{}.''.format(num_messages, pluralize(num_messages))

o:

''You have %d message%s'' % (num_messages, pluralize(num_messages))

Django pluralize docs: https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#pluralize


Usando un formateador personalizado :

import string class PluralFormattter(string.Formatter): def get_value(self, key, args, kwargs): if isinstance(key, int): return args[key] if key in kwargs: return kwargs[key] if ''('' in key and key.endswith('')''): key, rest = key.split(''('', 1) value = kwargs[key] suffix = rest.rstrip('')'').split('','') if len(suffix) == 1: suffix.insert(0, '''') return suffix[0] if value <= 1 else suffix[1] else: raise KeyError(key) data = {''tree'': 1, ''bush'': 2, ''flower'': 3, ''cactus'': 0} formatter = PluralFormattter() fmt = "{tree} tree{tree(s)}, {bush} bush{bush(es)}, {flower} flower{flower(s)}, {cactus} cact{cactus(i,us)}" print(formatter.format(fmt, **data))

Salida:

1 tree, 2 bushes, 3 flowers, 0 cacti

ACTUALIZAR

Si está usando Python 3.2+ (se agregó str.format_map ), puede usar la idea de OP (ver comentario) que usa dict personalizado.

class PluralDict(dict): def __missing__(self, key): if ''('' in key and key.endswith('')''): key, rest = key.split(''('', 1) value = super().__getitem__(key) suffix = rest.rstrip('')'').split('','') if len(suffix) == 1: suffix.insert(0, '''') return suffix[0] if value <= 1 else suffix[1] raise KeyError(key) data = PluralDict({''tree'': 1, ''bush'': 2, ''flower'': 3, ''cactus'': 0}) fmt = "{tree} tree{tree(s)}, {bush} bush{bush(es)}, {flower} flower{flower(s)}, {cactus} cact{cactus(i,us)}" print(fmt.format_map(data))

Salida: igual que el anterior.