Replace the exact number from line of text even if the number is repeated using regular expression Python

Viewed 35

I have one input file. sample.txt: is a text file that contains multiple functions with parameters and values.

Sample.txt:

step(change_lane in [1.5..2]s) # From: 'change_lane: [1.5..2]s'
step(stop_lane in [1.8..21]s) # From: 'stop_lane: [1.5..2]s'
step(stay_lane in [1.7..9]s) # From: 'stay_lane: [1.5..2]s'
The new lane change is == 25
.......

My code is the following:


for line in open('sample.txt'):
    match = re.search('change_lane', line)
    if match:
        # Finds numbers in line, outputs a list of numbers in line
        x = re.findall(r'(\d+(?:\.\d+)?)', line)
        
        # Gets first/second number from list
        print(f"This is line: {x}")
        get_num1 = x[0]
        get_num2 = x[1]
       
        #Replace first number found with number 200
        rep_num1 = re.sub(r'\b'+get_num1+r'\b','200',line)
        print(f"Rep1: {rep_num1}")
        #Replace second number found with number 17.21 under new edited line.
        rep_num2 = re.sub(r'\b'+get_num2+r'\b','17.21',rep_num1)
    
        #Old text line will equal to edited line
        line = rep_num2
        print(f"This is the new line: {line}")

The code will search through the text and match a phrase in this case "change_lane". If it matches it will find all numbers and output them as a list: [1.5,2,1.5,2].I am only interested in changing the first two numbers as the rest is a comment. Next, I will replace first number in the list with number 200. Now rep_num1 will become the new line as such:

keep(change_lane in [200..2]s) # From: 'change_lane: [200..2]s

help here: Then, I want the code to replace the number 2 with 17.21 as such:

keep(change_lane in [200..17.21]s) # From: 'change_lane: [200..17.21]s

But instead it replaces all number '2's with 17.21 as such:

keep(change_lane in [17.2100..17.21]s) # From: 'change_lane: [17.2100..17.21]s

How can I write the regular expression to find the exact number and replace that number even if the number is repeated?

1 Answers

You might use a single pattern to find the right line and then do the replacement for the numbers.

The pattern captures 3 groups that you can use in the replacement. The matches in between the groups are the numbers that you want to replace.

Explanation

^(.*?\bchange_lane\b.*?\[)\d+(?:\.\d+)?(\.+)\d+(?:\.\d+)?(]s\)\s+#)
  • ^ Start of string
  • ( Group 1
    • .*?\bchange_lane\b Match as least as possible characters until change_lane
    • .*?\[ Match the first occurrence of [
  • ) Close group 1
  • \d+(?:\.\d+)? Match the number
  • (\.+) Group 2, match 1+ dots
  • \d+(?:\.\d+)? Match the second occurrence of the number
  • (]s\)\s+#) Group 3, match the last part till the #

Regex demo

import re

pattern = r"^(.*?\bchange_lane\b.*?\[)\d+(?:\.\d+)?(\.+)\d+(?:\.\d+)?(]s\)\s+#)"

s = ("step(change_lane in [1.5..2]s) # From: 'change_lane: [1.5..2]s'\n"
            "step(stop_lane in [1.8..21]s) # From: 'stop_lane: [1.5..2]s'\n"
            "step(stay_lane in [1.7..9]s) # From: 'stay_lane: [1.5..2]s'\n"
            "The new lane change is == 25")

subst = r"\g<1>200\g<2>17.21\g<3>"

result = re.sub(pattern, subst, s, 0, re.MULTILINE)

print (result)

Output

step(change_lane in [200..17.21]s) # From: 'change_lane: [1.5..2]s'
step(stop_lane in [1.8..21]s) # From: 'stop_lane: [1.5..2]s'
step(stay_lane in [1.7..9]s) # From: 'stay_lane: [1.5..2]s'
The new lane change is == 25
Related