简体   繁体   中英

Python replace whole word using lookahead/lookbehind

Using look ahead and look behind in regex how can i replace the following words succefully using python without replacing other words that appear similar.

css = '''
     selection-background-color: primary;
     selection-background-color:primary;
     selection-color: text-primary;
     selection-background-color: primary-text;
'''

I was trying to use this (?<?\w)primary(?=\w) based on what I was researching online but I'm not super familiar with regex and the best way to write this.

I would expect my results from the code above to create this...

css = css.replace('primary', 'rgb(255,255,255)')
css = css.replace('primary-text', 'red')
css = css.replace('text-primary', 'green')

returns:

css = '''
     selection-background-color: rgb(255,255,255);
     selection-background-color:rgb(255,255,255);
     selection-color: green;
     selection-background-color: red;
'''

Normally you would use word boundaries ( \b ) to resolve this type of problem, however because your words can appear as part of a multi-part word with the parts separated by a hyphen (which matches a word boundary) this won't work. Instead, you can match with forward and backward negative lookarounds for a character or a hyphen around the word:

import re

css = '''
     selection-background-color: primary;
     selection-background-color:primary;
     selection-color: text-primary;
     selection-background-color: primary-text;
'''

css = re.sub(r'(?<![a-z-])primary(?![a-z-])', 'rgb(255,255,255)', css)
css = re.sub(r'(?<![a-z-])primary-text(?![a-z-])', 'red', css)
css = re.sub(r'(?<![a-z-])text-primary(?![a-z-])', 'green', css)
        
print(css)

Output:

selection-background-color: rgb(255,255,255);
selection-background-color:rgb(255,255,255);
selection-color: green;
selection-background-color: red;

You can also try a dictionary-based approach, making a regex out of the keys of the dictionary and replacing with the matching value:

replacements = {
    'primary' : 'rgb(255,255,255)',
    'primary-text' : 'red',
    'text-primary' : 'green'
}
regex = '(?<![a-z-])(?:' + '|'.join(replacements.keys()) + ')(?![a-z-])'

css = re.sub(regex, lambda m: replacements[m.group()], css)

print(css)

Since all your replacements are on values in colon-delimited key-value pairs, you can instead use a dict that maps values to their replacements and use re.sub with a regex that groups the values and the characters before them to replace the matches with a function that returns the values replaced by the mapped replacements if they are in the mapping table:

mapping = {
    'primary': 'rgb(255,255,255)',
    'primary-text': 'red',
    'text-primary': 'green'
}
css = re.sub(
    r'(:\s*)(.*);',
    lambda m: m.group(1) + mapping.get(m.group(2), m.group(2)),
    css
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM