-1

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;
'''
JokerMartini
  • 5,674
  • 9
  • 83
  • 193
  • Does this answer your question? [Regex match entire words only](https://stackoverflow.com/questions/1751301/regex-match-entire-words-only) – Nick Dec 07 '20 at 03:17
  • Those appear like good references but if i stick those into regex101.com with python neither of them work sadly – JokerMartini Dec 07 '20 at 03:23

2 Answers2

1

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)
Nick
  • 138,499
  • 22
  • 57
  • 95
0

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
)
blhsing
  • 91,368
  • 6
  • 71
  • 106