3

Update: as up to now (2019-09), masking leading or trailing zeros in decimal numbers formatted to string seems to be unsupported in Python. You will need to use a workaround to get something like '.01' from the number 0.0101 (assuming 3 decimal places desired).

I would even argue that it's a good thing not to support such a format since

  • I'd consider '0.01' be better in terms of readability than '.01'
  • '0.010' carries information (3 digits of precision...) that is lost in '0.01'

If desired anyway, one could use one of the suggestions below. Thank you all for contributing.

Q: I'm looking for a way to output floating point numbers as strings, formatted without leading/trailing zeros. Is there a way to do this with '{ }'.format() or f-string? I searched the internet but didn't find anything. Did I just miss it or is it not possible (Python 3.7)? What I have in mind is basically

some_number = 0.3140
string = f'{some_number:x}' # giving '.314'

that gives the output string '.314'.. So is there an x that does this?

Of course one could work-around with lstrip / rstrip as described e.g. here or similar here:

In [93]: str(0.3140).lstrip('0').rstrip('0')
Out[93]: '.314'

but it would be more convenient to use only an f-string. Since I can use that for other formatting options, optionally calling strip demands additional lines of code.

FObersteiner
  • 22,500
  • 8
  • 42
  • 72
  • Possible duplicate of [Pythonic way to strip all 0's from the front of a string](https://stackoverflow.com/questions/10860048/pythonic-way-to-strip-all-0s-from-the-front-of-a-string) – gpk27 Jul 25 '19 at 07:25
  • @gpk, I am NOT looking for a `strip` method. I made an edit to clarify. – FObersteiner Jul 25 '19 at 07:26
  • 1
    oh, alright @MrFuppes, maybe this can help - https://stackoverflow.com/questions/10303797/print-floating-point-values-without-leading-zero – gpk27 Jul 25 '19 at 07:35
  • @gpk27, thanks, but I looked into the answers that were given in the [Q&A you suggested](https://stackoverflow.com/questions/10303797/print-floating-point-values-without-leading-zero). Seems to be another hack; defining new classes it not what I have in mind. – FObersteiner Jul 25 '19 at 08:26
  • 1
    I don't know if this fits your requirement, but you can combine f-strings with the `strip()` methods by using `string = f'{(str(some_number).lstrip("0").rstrip("0"))}' `. – Jack Fleeting Sep 02 '19 at 23:48
  • @JackFleeting: thanks for the comment, I also was thinking about something like that. Basically I think now after some additional research that Python number-to-string format options do not support masking of leading/trailing zeros (I think it is a good thing not to support this btw.). One *must* use the `strip` work-around. – FObersteiner Sep 03 '19 at 08:02

4 Answers4

1

just to mention it here... if you use numpy there's also the function np.format_float_positional() that gives you full control of how to display numbers as strings and trim trailing zeros...

from the doc of np.format_float_positional:

Format a floating-point scalar as a decimal string in positional notation.

Provides control over rounding, trimming and padding. Uses and assumes IEEE >unbiased rounding. Uses the "Dragon4" algorithm.

getting rid of the leading zero is then just a simple check whether we're dealing with a number that starts with 0 or not

import numpy as np
def format_float(x, trim_leading=True, **kwargs):
    s = np.format_float_positional(x, **kwargs)
    if trim_leading is True and int(x) == 0 and len(s) > 1:
        s = s.replace("0.", ".")
    return s
format_float(0.0234001232, trim_leading=True, precision=4)
>>> '.0234'
format_float(0.0234001232, trim_leading=False, precision=4)
>>> '0.0234'
format_float(0.0234001232, precision=8)
>>> '0.02340012'
format_float(12.000558, precision=2, trim="-", fractional=False)
>>> '12'
FObersteiner
  • 22,500
  • 8
  • 42
  • 72
raphael
  • 2,159
  • 17
  • 20
0

if you want to just strip 0 from floating numbers you could use this "hack"

"." + str(0.314).split("0.")[-1]

this is in no way an elegant solution, but it will get the job done

also if you want to use .format as well you don't need another line, you could just

"." +str(0.314).split("0.")[-1].format('')
Imtinan Azhar
  • 1,725
  • 10
  • 26
  • sorry, I think my question was a bit unclear. I made an edit to clarify. – FObersteiner Jul 25 '19 at 07:25
  • I understood your question, try what I have mentioned above, you will achieve what you want, try it out `string = "." + str(some_number).split("0.")[-1]` – Imtinan Azhar Jul 25 '19 at 07:30
  • your hack works, although I think `lstrip` is clearer in terms of code readability - but the question is: how to achieve it with `'{ }'.format()` – FObersteiner Jul 25 '19 at 08:12
0

If you want to use format(), then try as below.

print("Hello {0}, your balance is {1}.".format("Adam", "0.314".lstrip('0')))

Just use lstrip() within format function, you don't need to write additional line of code.

FObersteiner
  • 22,500
  • 8
  • 42
  • 72
SUN
  • 181
  • 5
  • this is about how to use ONLY `'{}'.format()`, i.e. what you put in the curly braces. As I stated in the question, "find x" to get `'{x}'.format(0.314) == '.314'`. Furthermore, the input is of numeric type, not string. – FObersteiner Jul 25 '19 at 14:49
0

here's a helper function that I came up with since the strip workaround can't be avoided:

def dec2string_stripped(num, dec_places=3, strip='right'):
    """
    Parameters
    ----------
    num : float or list of float
        scalar or list of decimal numbers.
    dec_places : int, optional
        number of decimal places to return. defaults to 3.
    strip : string, optional
        what to strip. 'right' (default), 'left' or 'both'.

    Returns
    -------
    list of string.
        numbers formatted as strings according to specification (see kwargs).
    """
    if not isinstance(num, list): # might be scalar or numpy array
        try:
            num = list(num)
        except TypeError: # input was scalar
            num = [num]

    if not isinstance(dec_places, int) or int(dec_places) < 1:
        raise ValueError(f"kwarg dec_places must be integer > 1 (got {dec_places})")

    if strip == 'right':
        return [f"{n:.{str(dec_places)}f}".rstrip('0') for n in num]
    if strip == 'left':
        return [f"{n:.{str(dec_places)}f}".lstrip('0') for n in num]
    if strip == 'both':
        return [f"{n:.{str(dec_places)}f}".strip('0') for n in num]
    raise ValueError(f"kwarg 'strip' must be 'right', 'left' or 'both' (got '{strip}')")
FObersteiner
  • 22,500
  • 8
  • 42
  • 72