给定一个
int
s的字典,我试图用每个数字格式化一个字符串,以及项目的复数形式。
样本输入
dict
:
data = {'tree': 1, 'bush': 2, 'flower': 3, 'cactus': 0}
样本输出
str
:
'My garden has 1 tree, 2 bushes, 3 flowers, and 0 cacti'
它需要使用任意格式的字符串。
我想出的最好的解决方案是一个
PluralItem
类来存储两个属性,n
(原始值)和s
(字符串's'
如果是复数,空字符串''
如果不是).针对不同的复数方法进行子分类
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'
然后通过理解和
dict
映射制作一个新的classes
:
classes = {'bush': PluralES, 'cactus': PluralI, None: PluralItem}
plural_data = {key: classes.get(key, classes[None])(value) for key, value in data.items()}
最后,格式字符串和实现:
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))
输出如下:
My garden has 1 tree, 2 bushes, 3 flowers, and 0 cacti
对于这样一个无疑是普遍的需求,我犹豫是否要放弃这样一个复杂的解决方案。
有没有办法使用内置的
format
方法和最少的附加代码来格式化这样的字符串?伪代码可能是这样的:
"{tree} tree{tree(s)}, {bush} bush{bush(es)}, {flower} flower{flower(s)}, {cactus} cact{cactus(i,us)}".format(data)
如果值是复数,括号返回内容,或者如果内容有逗号,表示复数/单数
检查 inflect 包。它将使事物多元化,并进行大量其他语言欺骗。有太多的情况需要自己特例!
来自上面链接的文档:
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))
对于您的具体示例:
{print(str(count) + " " + p.pluralize(string, count)) for string, count in data.items() }
当您只有两种形式,并且只需要快速而肮脏的修复时,请尝试
's'[:i^1]
:
for i in range(5):
print(f"{i} bottle{'s'[:i^1]} of beer.")
输出:
0 bottles of beer.
1 bottle of beer.
2 bottles of beer.
3 bottles of beer.
4 bottles of beer.
说明:
^
是按位运算符异或(异或)。
i
为零时,
i ^ 1
计算为
1
。
's'[:1]
给
's'
.
i
为一时,
i ^ 1
计算为
0
。
's'[:0]
给出空字符串。
i
大于一时,
i ^ 1
求值为大于
1
的整数(以3,2,5,4,7,6,9,8...开头,见https:// oeis.org/A004442 了解更多信息)。 Python 并不介意,它会尽可能多地返回
's'
的字符,即
's'
.
!=
而不是
^
构建解决方案。扩展
'es'[:2*i^2]
。更一般地,对于 n 字符的复数形式,在前面的表达式中用 n 替换
2
。对面
's'[i^1:]
在第三人称单数动词中添加's':
for i in range(5):
print(f"{i} bottle{'s'[:i^1]} of beer lie{'s'[i^1:]} on the wall.")
输出:
0 bottles of beer lie on the wall.
1 bottle of beer lies on the wall.
2 bottles of beer lie on the wall.
3 bottles of beer lie on the wall.
4 bottles of beer lie on the wall.
Python 将第一种形式解释为 [:stop]
,将第二种形式解释为
[start:]
.复制
for i in range(5):
print(f"{i} grande{(s:='s'[:i^1])}, belle{s} et solide{s} bouteille{s}.")
输出:
0 grandes, belles et solides bouteilles.
1 grande, belle et solide bouteille.
2 grandes, belles et solides bouteilles.
3 grandes, belles et solides bouteilles.
4 grandes, belles et solides bouteilles.
注意强制性括号,并注意新变量不是 f 字符串的局部变量。当然,在“正常”样式中,您应该将其写成两行(赋值 + f-string)。
自定义格式化程序:
import string
class PluralFormatter(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 = PluralFormatter()
fmt = "{tree} tree{tree(s)}, {bush} bush{bush(es)}, {flower} flower{flower(s)}, {cactus} cact{cactus(i,us)}"
print(formatter.format(fmt, **data))
输出:
1 tree, 2 bushes, 3 flowers, 0 cacti
更新
如果您使用的是 Python 3.2+(添加了),您可以使用使用自定义字典的 OP(见评论)的想法。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))
输出:同上。
You have {{ num_messages }} message{{ num_messages|pluralize }}.
但是你可以将它导入到你的代码中并直接调用它:
from django.template.defaultfilters import pluralize
f'You have {num_messages} message{pluralize(num_messages)}.'
'You have {} message{}.'.format(num_messages, pluralize(num_messages))
'You have %d message%s' % (num_messages, pluralize(num_messages))
[singular, plural]
,然后制作一个小函数返回给定数量的索引:
def sp(num):
if num == 1:
return 0
else:
return 1
然后它像这样工作:
lemon = ["lemon", "lemons"]
str = f"Hi I have bought 2 {lemon[sp(2)]}"
实际上,如果你拆分这个词,你可以一次得到很多:
s = ["","s"]
str = f"Hi I have 1 cow{s[sp(1)]}"
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'
格式为
always/singular/plural
,其中
singular
(然后是
plural
)可选。所以
"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"
然后对于你的例子,一个只是做:
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'
https://gist.github.com/elidchan/40baea13bb91193a326e3a8c4cbcaeb9
特点:
"""
Usage:
>>> from utils.verbiage import Plurality
>>> f"We have {Plurality(0, 'g/oose/eese')}."
'We have 0 geese.'
>>> f"We have {Plurality(1, 'g/oose/eese')}."
'We have 1 goose.'
>>> f"We have {Plurality(2, 'g/oose/eese')}."
'We have 2 geese.'
>>> oxen = Plurality('ox/en')
>>> oxen.template_formatter
'1=$n $thing;n=$n $things'
>>> f"We have {oxen(0)}."
'We have 0 oxen.'
>>> f"We have {oxen(1)}."
'We have 1 ox.'
>>> f"We have {oxen(2)}."
'We have 2 oxen.'
>>> cows = Plurality('/cow/kine', '0=no $things', '1=$a $thing')
>>> cows.template_formatter
'0=no $things;1=a $thing;n=$n $things'
>>> f"We have {cows(0)}."
'We have no kine.'
>>> f"We have {cows(1)}."
'We have a cow.'
>>> f"We have {cows(2)}."
'We have 2 kine.'
>>> 'We have {:0=no $things;0.5=half $a $thing}.'.format(Plurality(0, 'octop/us/odes'))
'We have no octopodes.'
>>> 'We have {:octop/us/odes;0=no $things;0.5=half $a $thing}.'.format(Plurality(0.5))
'We have half an octopus.'
>>> 'We have {:4;octop/us/odes;0=no $things;0.5=half $a $thing}.'.format(Plurality())
'We have 4 octopodes.'
>>> data = {'herb': 1, 'bush': 2, 'flower': 3, 'cactus': 0}
>>> s = "We have {herb:herb/s}, {bush:bush/es}, {flower:flower/s}, and {cactus:cact/us/i}."
>>> s.format_map({k: Plurality(v) for k, v in data.items()})
'We have 1 herb, 2 bushes, 3 flowers, and 0 cacti.'
>>> vague = Plurality('0=no $things;1=$a $thing;2=a couple $things;n=some $things')
>>> s.format_map({k: vague(v) for k, v in data.items()})
'We have an herb, a couple bushes, some flowers, and no cacti.'
"""