Python 3 float to formatted string to always fill a fixed number of characters - Page 1
Forum section: electronics / general

author: RoGeorge
author_rank: Super Contributor
timestamp: January 28, 2025, 10:03:07 pm
content: For example, if there are 6 empty spaces (chars) to fill, and all 6 has to be populated, no spaces, no scientific format:"0.0000" for float 0.0"0.0100" for float 0.01"435.67" for float 435.666983"-2.000" for float -2.0"######" for float 100000000.0 or other overflowIs it possible to do that using formatted strings only, without writing additional float to string functions?Python version is 3.10.12. I've searched online already, read examples and docs, but couldn't figure.

author: mariush
author_rank: Super Contributor
timestamp: January 28, 2025, 10:29:36 pm
content: not sure if there's some built in function like printf that would do it, but you could write your ownsomething like:pseudo codenr = 1235max_digits = 6is_negative = falsehas_decimals = falseif nr < 0max_digits = max_digits -1is_negative = truenr = -nr;if int (nr) != nrmax_digits = max_digits - 2has decimals = truemax_value = 10 ^ max_digits - 1if nr > max_valueresult = '######';elseresult = float_to_string (nr)if has_decimals == falseresult = result + '.0'if is_negative ==trueresult = '-' + resultif len(result) > 6result = left(result,6)while len(result)<6result = result + '0';something like this....the only case not treated here is the 435.6669 -> 435.667 but I suppose you could figure out how many decimals need to be added and then do a round(nr, 3) (for number above) or something like that

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 29, 2025, 12:06:48 am
content: I don't think there is a format that can achieve the very specific formatting you want here, but here is my take - while there may be more efficient ways of doing it, it's a pretty short function and seems to do what you want:Code:def StrFormat(x, length = 6):nip = len(str(int(x)))nfp = length - nip - 1 if nip < length else 0s = '{number:{ip}.{fp}f}'.format(number = x, ip = nip, fp = nfp)return '#' * length if len(s) > length else ' ' + s if len(s) < length else sYou can specifiy a string length different than 6 as I made it a parameter.The only case you didn't specify is if the length of the integer part converted to string is the target length minus 1, as in this case, you didn't specify what you wanted the string to be filled with.So, with my function, it will pad the string with a leading whitespace.Like:StrFormat(-2, 3)will yield: ' -2'But if you prefer the above to yield: '-2.' (so a trailing period), the change is easy to do.

author: John B
author_rank: Frequent Contributor
timestamp: January 29, 2025, 12:17:25 am
content: You'll probably want to use the string.format functions.https://www.w3schools.com/python/ref_string_format.aspI've done similar things with integer format functions. Take for example:num = 5example_string = f'{"{:02d}".format(num)}'turns the integer 5 into a string of 05

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 29, 2025, 12:38:49 am
content: Ah, good ol' Fortran formatting.The basic idea is to doCode:def custom_format(value, length):decimals = length - 2while decimals >= 1:s = ('%%.%df' % decimals) % valueif len(s) == length:return selse:decimals -= 1return '#' * lengthstarting with the maximum number of fractional decimal digits, then reducing the count until it fits in the given space.We can speed it up by checking how many integer digits are needed first, but it will still do two iterations when rounding causes the number of integer decimal digits to change; for example, when formatting -99.995 to length 6.Code:import mathdef custom_format(value, length):magnitude = abs(value)if magnitude < 10.0:decimals = int(length - 2.5 + math.copysign(0.5, value))else:decimals = int(length - 1.5 + math.copysign(0.5, value) - math.ceil(math.log10(magnitude)))while decimals >= 1:s = ('%%.%df' % decimals) % valueif len(s) == length:return selse:decimals -= 1return '#' * lengthThe sub-expressionint(0.5 - math.copysign(0.5,value)evaluates to1whenvaluehas a negative sign, and0otherwise. The expression'%%.%df' %Ninterpolates to'%.Nf', so the expression('%%.%df' %decimals) %valueinterpolates to a decimal string representingvalueusingdecimalsdecimal digits.Quote from: SiliconWizard on January 29, 2025, 12:06:48 amNeeds work:StrFormat(-99.994, 6) == '-99.99',StrFormat(-100.0, 6) == '-100.0', butStrFormat(-99.995, 6) == '######'.

author: golden_labels
author_rank: Super Contributor
timestamp: January 29, 2025, 03:52:01 am
content: I would start with thegeneral number format (g)in “alternate form” (#), because it offers the output you want for most inputs, and work around the few special cases.This seems about right:Code:f'{round(x, 4):#.5g}'[:6] if (x >= -9999 and x <= 99999) else '######'Note you didn’t specify how 5-digit positive and 4-digit negative numbers are to be formatted, so I assumed the final trailing dot is ok.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 29, 2025, 04:11:24 am
content: Quote from: Nominal Animal on January 29, 2025, 12:38:49 amI see. Here's what should be a fix (with still the same approach).Code:def StrFormat(x, length = 6):nip = len(str(int(x)))nfp = length - nip - 1 if nip < length else 0x = round(x, nfp)nip = len(str(int(x)))nfp = length - nip - 1 if nip < length else 0s = '{number:{ip}.{fp}f}'.format(number = x, ip = nip, fp = nfp)return '#' * length if len(s) > length else ' ' + s if len(s) < length else s

author: ejeffrey
author_rank: Super Contributor
timestamp: January 29, 2025, 04:45:05 am
content: Quote from: RoGeorge on January 28, 2025, 10:03:07 pmNo. If for no other reason than all of the standard python float formatting options will format any number you give them. They don't have out of range handling, and they will use more than the specified width if needed, rather than show incorrect output. They also print nan and inf if you have those as inputs.If the number is in range -99999.5 < x < 999999.5 then %.6f followed by truncating the string to 6 characters should be at least close to what you want?

author: RoGeorge
author_rank: Super Contributor
timestamp: January 29, 2025, 05:49:39 am
content: From the answers I understand that I'll have to prepare the string myself. So, not possible by using only the native python formats, but I've learned some new tricks from your code examples.Thank you all.

author: Picuino
author_rank: Super Contributor
timestamp: February 03, 2025, 06:28:28 pm
content: Interesting PEP FYI:https://peps.python.org/pep-3101/Perhaps you should add one more character to the negative numbers, to keep the precision the same in all cases. Or add a space or a + sign to positive numbers.