Q:

Why regex is not working? 

I need to replace all occurences of normal whitespaces in «статья 1», «статьи 2» etc.  with non-breaking spaces.  
The construction below works fine:
 re.sub('(стат.{0,4}) (\d+)', r'\1&#x00A0;\2', text) # 'r' in repl is important, otherwise the word is not replaced correctly, at least for texts in Russian. 

however, I do not want to repeatedly use re.sub for «статья», then for «пункт», then for the names of months, I want to have a dictionary with regex expressions and replacements.  Here's my code, but it does not work as expected: 'статья 1 статьи 2' should look like 'статья(non-breaking space here)1 статьи(non-breaking space here)2':
 import re

 text = 'статья 1 статьи 2'
 dic = {'(cтат.{0,4}) (\d+)' : r'\1&#x00A0;\2'}

 def replace():
     global text
     final_text = ''
     for i in dic:
         new_text = re.sub(str(i), str(dic[i]), text)
         text = new_text
     return text

 print (replace())

A:

The problem is that you copied and pasted wrong. 
This pattern works:
'(стат.{0,4}) (\d+)'

This one doesn't:
'(cтат.{0,4}) (\d+)'

Why?  Because in the first one, and in your search string, that first character is a U+0441, a Cyrillic small Es.  But in the second one, it's a U+0063, a Latin small C. Of course the two look identical in most fonts, but they're not the same character. 

So, how can you tell?  Well, when I suspected this problem, here's what I did:
>>> a = '(стат.{0,4}) (\d+)' # copied and pasted from your working code
>>> b = '(cтат.{0,4}) (\d+)' # copied and pasted from your broken code
>>> print(a.encode('unicode-escape').decode('ascii'))
(\u0441\u0442\u0430\u0442.{0,4}) (\\d+)
>>> print(b.encode('unicode-escape').decode('ascii'))
(c\u0442\u0430\u0442.{0,4}) (\\d+)

And the difference is obvious: the first one has a \u0441 escape sequence where the second one has a plain ASCII c.

