\b is according to the python documentation:
Matches the empty string, but only at the beginning or end of a word. A word is defined as a sequence of word characters. Note that formally, \b is defined as the boundary between a \w and a \W character (or vice versa), or between \w and the beginning/end of the string. This means that r'\bfoo\b' matches 'foo', 'foo.', '(foo)', 'bar foo baz' but not 'foobar' or 'foo3'.
By default Unicode alphanumerics are the ones used in Unicode patterns, but this can be changed by using the ASCII flag. Word boundaries are determined by the current locale if the LOCALE flag is used. Inside a character range, \b represents the backspace character, for compatibility with Python’s string literals.
In conjunction with lookahead and lookbehinds, this is useful to replace a word with another word. Here foo is replaced by bar:
>>> re.sub(r"(?<=\b)foo(?=\b)", "bar", "baz foo baz")
'baz bar baz'
>>> re.sub(r"(?<=\b)foo(?=\b)", "bar", "foo baz")
'bar baz'
>>> re.sub(r"(?<=\b)foo(?=\b)", "bar", "baz foo")
'baz bar'
Now if I want to replace a word ending with a dot, this seems to not be enough:
>>> re.sub(r"(?<=\b)foo\.(?=\b)", "bar", "baz foo. baz")
'baz foo. baz'
Here I would have expected the result to be baz bar baz.
What am I doing wrong? How can I fix this?