Ok I fixed the second point too.
Now I iterate only over NavigableStrings, not all elements:
def elements(x):
while x is not None:
if isinstance(x, bs4.NavigableString):
if len(x.string.strip('\n ')) > 0:
yield x
x = x.next_element
Then in the loop, I extract the string, recording its position in the parent element:
parent = e.parent
i = parent.contents.index(e)
x = e.extract()
and replace it (the string) with a new list which includes the newly created abbr tag:
xs = list(re.split(abbr_exp, x.string))
ys = join(functools.partial(new_abbr, abbr), xs)
for j, y in enumerate(ys):
parent.insert(i + j, y)
and it works!
See the gist for the updated script. Maybe someone will find it useful.