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.