Reputation: 492
I have a certain string fruits
as such:
Apples
Bananas
Pineapples
There is a carriage return \r
at the end of each line, as well as at the beginning and end of the string. Using RegEx, how would I go about appending : 1
to the end of the first line Apples
? I have tried the following to no avail:
re.sub("Apples(\r)", "\1:1", fruits)
My thinking was that \1
should replace what's in the brackets (\r)
, however everything in the pattern is being replaced.
Upvotes: 2
Views: 77
Reputation: 196
Having \r as your fruit separator makes it awkward to print things out; so for the purposes of this answer I am going to use the @ character in its place. The code that follows works just the same if you assign \r to my separator variable and use your actual \r separated string for fruit_str.
Some explanation follows the code.
import re
def updateFruitQuantity(the_fruit, the_quantity, fruit_str, separator):
re_1 = r"(" + the_fruit + r")(:.*?|)" + separator
re_2 = r'\1:' + str(the_quantity) + separator
fruit_str = re.sub(re_1, re_2, fruit_str)
return(fruit_str)
separator = "@"
fruit_str = "@Apples@Bananas@Pineapples@"
print(fruit_str)
fruit_str = updateFruitQuantity("Pineapples", 25, fruit_str, separator)
print(fruit_str)
fruit_str = updateFruitQuantity("Bananas", 17, fruit_str, separator)
print(fruit_str)
fruit_str = updateFruitQuantity("Pineapples", 3, fruit_str, separator)
print(fruit_str)
fruit_str = updateFruitQuantity("Apples", 94, fruit_str, separator)
print(fruit_str)
fruit_str = updateFruitQuantity("Apples", 102, fruit_str, separator)
print(fruit_str)
And here is the code's output:
@Apples@Bananas@Pineapples@
@Apples@Bananas@Pineapples:25@
@Apples@Bananas:17@Pineapples:25@
@Apples@Bananas:17@Pineapples:3@
@Apples:94@Bananas:17@Pineapples:3@
@Apples:102@Bananas:17@Pineapples:3@
I am building separate regular expressions for the target text and for the replacement text.
These target expression assumes that each fruit:quantity is followed by the separator. There are two capture groups in the target expression -- each is surrounded by parenthesis. The second grouping is important in the target expression because it sweeps up any :quantity element that might be present.
The replacement expression starts with \1 which stands for the text matched by the first grouping in the target expression (eg "Apples"). That is followed by the colon and then the quantity string to be used. Doing it this way ensures that any existing :quantity is properly replaced with the new quantity and that it also works in the case where there were no existing :quantity. So for example in our third change you see the quantity for Pineapples go back from 25 to 3.
You will need another mechanism for adding new types of fruit to fruit_str as time went on.
Upvotes: 0
Reputation: 27388
What you are doing is matching "Apples\r"
, capturing the "\r"
in the process, and then replacing the entire match with "\r:1"
.
For this simple example, there's no need to capture matches to \r
, anyway, since the only thing that will match it is \r
. You can hard code that into the replacement string.
I'll assume you want the resulting string to be "\rApples: 1\rBananas\rPineapples\r
.
You can use a lookbehind so that Apples
is not consumed (though I hear that consuming one a day keeps the doctor away):
re.sub("(?<=Apples)\r", ": 1\r", fruits)
But you could also just do:
re.sub("Apples\r", "Apples: 1\r", fruits)
The lookbehind would be more useful if you wanted to add : 1
after each fruit:
re.sub("(?<=[^\r])\r", ": 1\r", fruits)
The above says find every \r
that follows a character that isn't an \r
, and replace them with : 1\r
. The result would then be:
# \rApples: 1\rBananas: 1\rPineapples: 1\r\r
Upvotes: 2
Reputation: 678
If you do
re.sub("A(B)", "\1C", "AB")
you will get BC
, because \1
is replaced by what is in the bracket.
To get AC
, you should do:
re.sub("(A)B", "\1C", "AB")
Upvotes: 1