48

尝试使用格式说明符打印一个小于 1 且没有前导零的浮点数。我想出了一些技巧,但我认为有一种方法可以删除格式说明符中的前导零。我在文档中找不到它。

问题

>>> k = .1337
>>> print "%.4f" % k
'0.1337'

哈克

>>> print ("%.4f" % k) [1:]
'.1337'
4

13 回答 13

34

这是另一种方式:

>>> ("%.4f" % k).lstrip('0')
'.1337'

它比[1:]它也适用于> = 1的数字更通用。

然而,这两种方法都不能正确处理负数。在这方面,以下方法更好:

>>> re.sub('0(?=[.])', '', ("%0.4f" % -k))
'-.1337'

不是特别优雅,但现在我想不出更好的方法。

于 2012-04-24T18:31:24.393 回答
12

尽管我喜欢可爱的正则表达式技巧,但我认为一个简单的函数是最好的方法:

def formatFloat(fmt, val):
  ret = fmt % val
  if ret.startswith("0."):
    return ret[1:]
  if ret.startswith("-0."):
    return "-" + ret[2:]
  return ret

>>> formatFloat("%.4f", .2)
'.2000'
>>> formatFloat("%.4f", -.2)
'-.2000'
>>> formatFloat("%.4f", -100.2)
'-100.2000'
>>> formatFloat("%.4f", 100.2)
'100.2000'

这样做的好处是易于理解,部分原因startswith是它是简单的字符串匹配而不是正则表达式。

于 2014-05-13T20:15:25.020 回答
7

一种可行的选择,无需正则表达式且负数大于 10

k = -.1337
("%.4f" % k).replace("-0","-").lstrip("0")
于 2014-02-21T18:57:35.020 回答
5

您可以使用以下MyFloat类而不是内置float类。

def _remove_leading_zero(value, string):
    if 1 > value > -1:
        string = string.replace('0', '', 1)
    return string


class MyFloat(float):
    def __str__(self):
        string = super().__str__()
        return _remove_leading_zero(self, string)

    def __format__(self, format_string):
        string = super().__format__(format_string)
        return _remove_leading_zero(self, string)

使用此类,您必须使用str.format函数而不是模运算符 ( %) 进行格式化。以下是一些示例:

>>> print(MyFloat(.4444))
.4444

>>> print(MyFloat(-.4444))
-.4444

>>> print('some text {:.3f} some more text',format(MyFloat(.4444)))
some text .444 some more text

>>> print('some text {:+.3f} some more text',format(MyFloat(.4444)))
some text +.444 some more text

如果您还想让类的模运算符 ( %)str以相同的方式运行,那么您必须通过子类化类来覆盖类的__mod__方法。str但它不会像覆盖类的__format__方法那么容易float,因为在这种情况下,格式化的浮点数可能出现在结果字符串的任何位置。

[注:以上所有代码都是用 Python3 编写的。您还必须__unicode__在 Python2中覆盖并且还必须更改super调用。]

PS:你也可以重写__repr__类似的方法__str__,如果你也想改变官方字符串MyFloat表示。




编辑:实际上您可以使用方法添加新语法来格式化字符串__format__。因此,如果您想保留这两种行为,即在需要时显示前导零,并且在不需要时不显示前导零。MyFloat您可以按如下方式创建类:

class MyFloat(float):
    def __format__(self, format_string):
        if format_string.endswith('z'):  # 'fz' is format sting for floats without leading the zero
            format_string = format_string[:-1]
            remove_leading_zero = True
        else:
            remove_leading_zero = False

        string = super(MyFloat, self).__format__(format_string)
        return _remove_leading_zero(self, string) if remove_leading_zero else string
        # `_remove_leading_zero` function is same as in the first example

并按如下方式使用此类:

>>> print('some text {:.3f} some more text',format(MyFloat(.4444)))
some text 0.444 some more text
>>> print('some text {:.3fz} some more text',format(MyFloat(.4444)))
some text .444 some more text


>>> print('some text {:+.3f} some more text',format(MyFloat(.4444)))
some text +0.444 some more text
>>> print('some text {:+.3fz} some more text',format(MyFloat(.4444)))
some text +.444 some more text


>>> print('some text {:.3f} some more text',format(MyFloat(-.4444)))
some text -0.444 some more text
>>> print('some text {:.3fz} some more text',format(MyFloat(-.4444)))
some text -.444 some more text

请注意,使用 'fz' 而不是 'f' 会删除前导零。

此外,上面的代码在 Python2 和 Python3 中都有效。

于 2014-05-17T21:27:50.283 回答
4
import re
re.sub("^(\-?)0\.", r'\1.', "%.4f" % k)

这很短,很简单,我找不到它不起作用的场景。

例子:

>>> import re
>>> re.sub("^(\-?)0\.", r'\1.', "%.4f" % 0)
'.0000'
>>> re.sub("^(\-?)0\.", r'\1.', "%.4f" % 0.1337)
'.1337'
>>> re.sub("^(\-?)0\.", r'\1.', "%.4f" % 1.337)
'1.3370'
>>> re.sub("^(\-?)0\.", r'\1.', "%.4f" % -0)
'.0000'
>>> re.sub("^(\-?)0\.", r'\1.', "%.4f" % -0.1337)
'-.1337'
>>> re.sub("^(\-?)0\.", r'\1.', "%.4f" % -1.337)
'-1.3370'
>>> re.sub("^(\-?)0\.", r'\1.', "%.4f" % 10.337)
'10.3370'
>>> re.sub("^(\-?)0\.", r'\1.', "%.4f" % -10.337)
'-10.3370'

编辑:如果您只考虑数字 > -10 和 < 10 以下将起作用:

("%.4f", k).replace('0.', '.')
于 2014-05-13T23:23:25.077 回答
4

我宁愿追求可读性和简单性:让我们独立处理符号和数字。还有一点内联的 if 语句永远不会伤害任何人。

k = -.1337
"".join( ["-" if k < 0 else "", ("%.4f" % abs(k)).lstrip('0')] )
于 2014-05-14T18:04:36.670 回答
4

使用.lstrip(), 后使用字符串格式转换为字符串:

>>> k = .1827412
>>> print ("%.4f"%(k)).lstrip('0')
.1827
>>> 

.lstrip()可用于删除字符串的任何前导字符:

>>> k = 'bhello'
>>> print k.lstrip('b')
hello
>>> print k.lstrip('bhel')
o
>>> print k.lstrip('bel')
hello
>>> 

从文档

string.lstrip(s[, 字符])

        返回删除前导字符的字符串副本

于 2014-05-15T02:19:31.613 回答
4

我很惊讶没有人提出更数学的方法来做到这一点:

n = 0.123456789
'.%d' % (n*1e4)

对我来说看起来好多了。:)

但有趣的是,你的速度最快。

$ python -mtimeit '".%d" % (0.123456789*1e4)'
1000000 loops, best of 3: 0.809 usec per loop
$ python -mtimeit '("%.4f"%(0.123456789)).lstrip("0")'
1000000 loops, best of 3: 0.209 usec per loop
$ python -mtimeit '("%.4f"%(0.123456789))[1:]'
10000000 loops, best of 3: 0.0723 usec per loop
于 2015-12-12T18:17:21.503 回答
2

由于我们只考虑 > -1 到 < 1,因此以下编辑将起作用。

import re
re.sub(r"0+\.", ".", %0.4f" % k)

这将保持符号,仅删除小数点左侧的数字。

于 2014-05-13T19:07:07.187 回答
1

Python 的标准库的 str.format() 可用于生成浮点值的字符串转换。然后可以对字符串进行操作以形成正数或负数的最终结果。

n = -.1234567890
print('{0}'.format('-' if n < 0 else '') + ('{:0.4}'.format(n).split('-')[1 if n < 0 else 0].lstrip('0')))
于 2014-05-18T16:14:50.647 回答
0

对于 Python 3

当您想要简单的东西并且不需要负数支持时:

f'{k:.4f}'.lstrip('0')

当您需要负数支持时,还有其他解决方案,包括 @nettux443 的出色正则表达式。

于 2018-11-04T15:17:53.040 回答
0

一个超短的(虽然不是很pythonic)单行,它也处理负数:

k = -.1337
"-"*(k<0)+("%.4f"%abs(k)).lstrip('0')
于 2019-08-12T09:43:41.400 回答
0

问题是打印一个没有前导零的浮点数,无论浮点数的符号如何。前导零总是在小数点之前。将打印的浮点数拆分为“0.”,然后将结果列表重新加入到“.”周围,如下所示:

>> flt = -.31415926

-0.31415926

>> '%.4f' % flt    # prints leading zero

'-0.3142'

>> '.'.join( ('%.4f' % flt).split('0.'))    # removes leading zero

'-.3142'

于 2019-09-13T05:26:04.483 回答