So i'm trying to replace normal numbers for roman numbers, but only the last number is replaced, so i wonder if there's a way to replace diferent values
sample = "Carl 5, 19 century"
numbers = re.findall(r'[0-9] ', sample)
for number in numbers:
num_int = int(number)
roman_number = int_to_Roman(num_int)
new_string = sample.replace(number, roman_number)
>>> Carl 5, XIX century
Here are some other results
sample = "Carl 19, 19 century"
>>> Carl XIX, XIX century
sample = "Carl 5"
>>> Carl V
CodePudding user response:
The below line in your code is taking the original string sample
and replacing the number
with the roman_number
but it is stored in a variable new_string
. In the next iteration, the code will again take the original string (which does not have the previous iteration's replacement stored) and replace the number
with roman_number
which is why when you are printing the new_string
after the loop, it is just showing the last number being replaced (which is the replacement in the last iteration of the loop).
new_string = sample.replace(number, roman_number)
There are 2 fixes for this. One is to store the modified string in the sample variable itself so that the loop can take the result of the last iteration and do further replacements.
sample = sample.replace(number, roman_number)
If you want to retain the original variable sample
, you can create a copy of the variable before the loop and do the replacement operation on the new_string
variable.
sample = "Carl 5, 19 century"
numbers = re.findall(r'[0-9] ', sample)
new_string = sample
for number in numbers:
num_int = int(number)
roman_number = int_to_Roman(num_int)
new_string = new_string.replace(number, roman_number)
CodePudding user response:
You can use re.sub()
and pass a callable (function) to the repl
argument. This callable takes one argument -- the match object, and returns the substitution for that match, so it would likely be a simple wrapper that extracts the match string from the match object and passes it on to int_to_Roman
:
def int_to_Roman_wrapper(match_obj):
return int_to_Roman(int(match_obj.group(0)))
sample = 'Carl 5, 15 century'
new_string = re.sub(r"\d ", int_to_Roman_wrapper, sample)
Which gives
new_string = 'Carl V, XV century'
This doesn't have the problem that the str.replace
approach does which tdelaney mentions in their comment:
.replace
will replace numbers throughout the string even if they are part of a larger number later on.sample = "Carl 5, 15 century"
would fail because the 5 in 15 would be replaced on the first match. The second match would try to replace 15, but its already been destroyed