Подтвердить что ты не робот

Печатать значения с плавающей запятой без начального нуля

Попытка использовать спецификатор формата для печати float, который будет меньше 1 без начального нуля. Я придумал немного взлома, но я предполагаю, что есть способ просто сбросить начальный ноль в спецификаторе формата. Я не мог найти его в документах.

Проблема

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

Hack

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

Ответ 1

Вы можете использовать следующий класс 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.




Изменить. На самом деле вы можете добавить новый синтаксис для форматирования sting с помощью метода __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.

Ответ 2

Вот еще один способ:

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

Это немного более общий, чем [1:], поскольку он также работает с числами >= 1.

Однако ни один из методов не обрабатывает отрицательные числа. В этом отношении лучше:

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

Не особенно элегантно, но сейчас я не могу придумать лучшего метода.

Ответ 3

Насколько мне нравятся симпатичные трюки регулярных выражений, я думаю, что простая функция - лучший способ сделать это:

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 - это простое совпадение строк, а не регулярное выражение.

Ответ 4

Один жизнеспособный вариант, который работает без регулярного выражения и с отрицательными числами больше 10

k = -.1337
("%.4f" % k).replace("-0","-").lstrip("0")

Ответ 5

Я бы лучше читал и прост, чем что-либо еще: пусть обрабатывает знак и цифры независимо. И немного в строке, если утверждение никогда никому не причиняло вреда.

k = -.1337
"".join( ["-" if k < 0 else "", ("%.4f" % abs(k)).lstrip('0')] )

Ответ 6

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'

Edit: Если вы рассматриваете только числa > -10 и < 10 Будет работать следующее:

("%.4f", k).replace('0.', '.')

Ответ 7

Используйте .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 [, chars])

          Возвращает копию строки с удаленными ведущими символами.

Ответ 8

Поскольку мы рассматриваем только > -1 в < 1, то будет выполнено следующее редактирование.

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

Это будет поддерживать знак, только удаляя цифру слева от десятичной дроби.

Ответ 9

Стандарт lib str.format() Python может использоваться для генерации преобразования строки значения float. Затем можно манипулировать строкой, чтобы сформировать конечный результат для положительного или отрицательного числа.

n = -.1234567890
print('{0}'.format('-' if n < 0 else '') + ('{:0.4}'.format(n).split('-')[1 if n < 0 else 0].lstrip('0')))

Ответ 10

Я удивлен, что никто не предложил более математический способ сделать это:

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