在自定义位置分割字符串的更简单/更快/更优雅的方式

时间:2018-03-14 04:30:10

标签: python python-3.x

我一直在寻找一种更简单的方法,但我不确定要使用哪些搜索参数。我有一个浮点数,我想舍入,转换为字符串,然后在字符串上指定自定义格式。我已经阅读了.format文档,但无法看到是否可以使用普通的字符串格式来完成此操作。

我想要的输出只是一个普通的字符串,每三个字符有空格,除了最后一个字符,它们应该在结尾之前有四个空格。

例如,我制作了这个错综复杂的函数,以低效的方式完成我想要的工作:

def my_formatter(value):
    final = []
    # round float and convert to list of strings of individual chars
    c = [i for i in '{:.0f}'.format(value)]
    if len(c) > 3:
        final.append(''.join(c[-4:]))
        c = c[:-4]
    else:
        return ''.join(c)
    for i in range(0, len(c) // 3 + 1, 1):
        if len(c) > 2:
            final.insert(0, ''.join(c[-3:]))
            c = c[:-3]
        elif len(c) > 0:
            final.insert(0, ''.join(c))
    return(' '.join(final))

e.g。

>>> my_formatter(123456789.12)
>>> '12 345 6789'
>>> my_formatter(12345678912.34)
>>> '1 234 567 8912'

非常感谢以更简单/更有效的方式做到这一点的指导。

5 个答案:

答案 0 :(得分:3)

角度略有不同但这使用第三方函数partition_all。简而言之,如果少于3个字符,我使用它将字符串分组为3个组加上最后一组。你可能更喜欢这个,因为没有for循环或条件,但它基本上是整容差异。

from toolz.itertoolz import partition_all
def simpleformat(x):
    x = str(round(x))
    a, b = x[:-4], x[-4:]
    strings = [''.join(x[::-1]) for x in reversed(list(partition_all(3, a[::-1])))]
    return ' '.join(strings + [b])

答案 1 :(得分:3)

试试这个:

def my_formatter(x):
    # round it as text
    txt = "{:.0f}".format(x)

    # find split indices
    splits = [None] + list(range(-4, -len(txt), -3)) + [None]

    # slice and rejoin
    return " ".join(
        reversed([txt[i:j] for i, j in zip(splits[1:], splits[:-1])]))

然后

>>> my_formatter(123456789.1)
12 345 6789
>>> my_formatter(1123456789.1)
112 345 6789
>>> my_formatter(11123456789.1)
1 112 345 6789

答案 2 :(得分:2)

这是一个非常简单的解决方案,使用相反顺序的元素循环,以便更容易计算索引:

num = 12345678912.34

temp = []
for ix, c in enumerate(reversed(str(round(num)))):
    if ix%3 == 0 and ix !=0: temp.extend([c, ' '])
    else: temp.extend(c)

''.join(list(reversed(temp)))

输出:

  

'1 234 567 8912'

使用列表推导,我们可以在一个非常混乱的行中执行此操作

num = 12345678912.34

''.join(list(reversed(list(''.join([c+' ' if(ix%3 == 0 and ix!=0) else c for ix, c in enumerate(reversed(str(round(num))))])))))
  

'1 234 567 8912'

答案 3 :(得分:2)

另一个方法是使用当前系统上的语言环境,并使用格式。

import locale

for v in ('fr_FR.UTF-8', 'en_GB.UTF-8'):
    locale.setlocale(locale.LC_NUMERIC, v)
    print(v, '>> {:n}'.format(111222333999))

答案 4 :(得分:1)

也可以分享另一个略有不同的变体,但仍然无法摆脱那种我们看不到的某种崇高方式的感觉。尚未将任何答案标记为正确,因为我确信python可以以更简单的方式做到这一点,不知何故。让我疯狂的是,如果我没记错的话,VB的格式命令可以处理这个问题(使用类似“### #### 0”的模式)。也许这只是一个不理解如何正确使用Python的.format的情况。

下面接受浮点数或小数以及表示拆分位置的列表。如果在使用最后一个分割位置后字符串中仍有数字,则重新应用该数字,直到它到达字符串的开头。

def format_number(num, pat, sep=' '):
    fmt = []
    strn = "{:.0f}".format(num)
    while strn:
        p = pat.pop() if pat else p
        fmt.append(strn[-p:])
        strn = strn[:-p] if len(strn) > p else ''
    return sep.join(fmt[::-1])

>>> format_number(123456789, [3, 4])
>>> '12 345 6789'
>>> format_number(1234567890, [3])
>>> '1 234 567 890'