How can I round a string made of numbers efficiently using Python?

Question:

Using Python 3…

I’ve written code that rounds the values for ArcGIS symbology labels. The label is given as a string like "0.3324 – 0.6631". My reproducible code is…

label = "0.3324 - 0.6631"
label_list = []
label_split = label.split(" - ") 
for num in label_split:
    num = round(float(num), 2) # rounded to 2 decimals
    num = str(num)
    label_list.append(num) 
label = label_list[0]+" - "+label_list[1]

This code works but does anyone have any recommendations/better approaches for rounding numbers inside of strings?

Asked By: Bojan Milinic

||

Answers:

You could use a regular expression to search for a number with more than two decimal places, and round it.

The regex bd+.d+b will find all numbers with decimal points that are surrounded by word boundaries in your string. It is surrounded in word boundaries to prevent it from picking up numbers attached to words, such as ABC0.1234.

Explanation of regex (Try online):

bd+.d+b

b        b     : Word boundary
  d+  d+       : One or more digits
     .          : Decimal point

The re.sub function allows you to specify a function that will take a match object as the input, and return the required replacement. Let’s define such a function that will parse the number to a float, and then format it to two decimal places using the f-string syntax (You can format it any way you like, I like this way)

def round_to_2(match):
    num = float(match.group(0))
    return f"{num:.2f}"

To use this function, we simply specify the function as the repl argument for re.sub

label = "0.3324 - 0.6631 ABC0.1234 0.12 1.234 1.23 123.4567 1.2"
label_rep = re.sub(r"bd+.d+b", round_to_2, label)

This gives label_rep as:

'0.33 - 0.66 ABC0.1234 0.12 1.23 1.23 123.46 1.20'

The advantage of this is that you didn’t need to hardcode any separator or split character. All numbers in your string are found and formatted. Note that this will add extra zeros to the number if required.

Answered By: Pranav Hosangadi

This solution doesn’t try to operate on a sequence but on the 2 values.

A bit more readable to me.

x, _, y = label.partition(" - ")
label = f"{float(x):.2f} - {float(y):.2f}"
Answered By: 0x0fba