Печатать значения с плавающей запятой без начального нуля
Попытка использовать спецификатор формата для печати float, который будет меньше 1 без начального нуля. Я придумал немного взлома, но я предполагаю, что есть способ просто сбросить начальный ноль в спецификаторе формата. Я не мог найти его в документах.
Проблема
>>> k = .1337
>>> print "%.4f" % k
'0.1337'
Hack
>>> print ("%.4f" % k) [1:]
'.1337'
Ответы
Ответ 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