3

I need to replace numbers (corners) that occur within a longer string that all look similar to this:

[ 17 plane_17 \ 23 25 17 99 150 248 \ noname ]

My function takes an "old" number to be replaced with a "new" number, and e.g. if that old number is 17 and the new is 19, then the outcome should be:

[ 17 plane_17 \ 23 25 19 99 150 248 \ noname ]

Note that only the numbers within \ \ should be replaced (these could also be / / ).

To do this I tried to set up a regex substitution with the intention of avoiding numbers outside of \ \ or / /: newplane = re.compile(r"[^[_] (" + str(oldcorner) + ")").sub(str(newcorner), oldplane)

I quickly realised that this doesn't work since regex searches from the start of the line and then fails if it doesn't match the pattern.

There must be some clever way of doing it still that I don't know about.. Any suggestions?

3
  • 1
    will they be between '\\', or single '\'? My first instinct would be to split it at '\' (or double), call plain old replace( old, new ) on every second element of the result and then join them back together at '\'. Not very pythonic though, interested to see if someone has a neat way Commented Mar 11, 2013 at 14:20
  • They'll all be either within single '\' or single '/'. That's not a bad idea! Would remove the regex too.... Commented Mar 11, 2013 at 14:23
  • yeah would keep things simple, not sure how you would handle both '\' and '/' in the same line though Commented Mar 11, 2013 at 14:25

2 Answers 2

4

You can use a callback function inside the sub part of the regex:

import re

def callback(match):
    return match.group(0).replace('17', '19')

s = "[ 17 plane_17 \ 23 25 17 99 150 248 \ noname ]"

s = re.compile(r'\\.+?\\').sub(callback, s)

print s

Prints:

[ 17 plane_17 \ 23 25 19 99 150 248 \ noname ]
Sign up to request clarification or add additional context in comments.

6 Comments

Where did the slashes get to?
Thanks for this, vpekar! Really clever with a callback function!
One issue with this: if there's a three digits (or more) number with the '17' as part of it, the callback will also replace it.
Callback means that first the callback runs and then sub? callback gets parameter s?
Does the question mark (non-greedy operator) make sense because there is no decision between greedy and non-greedy?
|
1

In addition to vpekar answer, you can also use backreferences of your pattern on the replacement string, so you can try to match all between / or \ and recreate the string using your new number and backreferences:

line = '[ 17 plane_17 \ 23 25 17 99 150 248 \ noname ]'
re.sub(r'([\\|/].*\s)(?:17)(\s.*[\\|/])', r'\g<1>19\2', line)

which returns:

'[ 17 plane_17 \ 23 25 19 99 150 248 \ noname ]'

3 Comments

Thanks asermax! I really like this one-liner solution too! There are clearly some gaps in my regex knowledge. Thanks!
Can you explain parts of it. sub has 3 parameters: old, new, string. You could leave the first r. Where is backreference no.1? no.2 is \2.
A non capturing group is not needed, simpler: re.sub(r'([\\|/].*\s)(17)(\s.*[\\|/])', r'\g<1>19\3', line)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.