You can capture those parts you want to keep.
And when replacing with .sub() method, enter the
captures parts using \\1 and \\2 in the replacer string.
import re
pattern = re.compile(r'(\S+)&(\S+)')
# `\S` means: any non-white character.
# see: https://docs.python.org/3/library/re.html
x = "apple&bob & john & smith"
x = pattern.sub("\\1\\2", x) # or also: re.sub(pattern, "\\1\\2", x)
x
## 'applebob & john & smith'
However, this replaces only 1 occurrence, the leftmost non-overlapping one, we need a function to replace all occurrences in the string. One can solve it using recursion:
def replace_all_pattern(pattern, s):
if bool(re.match(pattern, s)):
res = re.sub(pattern, "\\1\\2", s)
return replace_all_pattern(pattern, res)
else:
return s
replace_all_pattern(r"(\S+)&(\S+)", "abble&bob&john&smith")
## 'abblebobjohnsmith'
But this will be performance-wise less efficient than using look-arounds. So use this only if exactly one occurrence is to be replaced. In that case, preformance-wise, it is better than the look-arounds, but as soon as more than one occurrences are possible and have to be checked: use the look-arounds as pattern, because they will be more efficient.
re.compile(r'(?<=\S)&(?=\S)').&apple&bob & john & smith&?