很好的问题。问题是:
re.sub
不允许一个字符位于多个匹配组中;一旦某个字符属于某个匹配项,则会使用该字符,除非指定该匹配项为非匹配项。当使用星号进行匹配时,一个关键事实是单词边界位于星号和单词字符之间。下面是使用星号(the
{0}
{1}
,和
{2}
在
lambda
('', 'first', '*')
('', 'second', '*')
('', 'third', '*')
('', 'fourth', '*')
('', 'fifth', '')
当regex匹配器到达第一个匹配的末尾时,其光标位于第一个星号和单词之间
second
,这是一个词的边界。因此
second*
third*
等等。
但是,当使用下划线时,以下是相应的匹配项:
('', 'first', '_')
('_', 'third', '_')
('_', 'fifth', '')
当regex匹配器到达第一个匹配的末尾时,其光标位于第一个下划线和单词之间
,这是
不
一个词的界限。因为它已经传递了第一个下划线并且不在单词边界处,所以它不能匹配
(_|\b)second
第二
,并且您可以看到,该匹配包括
third
简而言之,第一个例子是“幸运”的,因为在传递分隔符字符之后,您将在单词边界中着陆,而第二个例子不是这样。
要解决这个问题,可以使用前瞻断言,它不会使用匹配的字符。
def replace_words(string, rep_dict, separator):
regex = r'({0}|\b)({1})((?={2}|\b).*?)'.format(
re.escape(separator), '|'.join(rep_dict.keys()), re.escape(separator)
)
return re.sub(
regex, lambda x: '{0}{1}{2}'.
format(x.group(1), rep_dict[x.group(2)], x.group(3)), string
)
('', 'first', '')
('*', 'second', '')
('*', 'third', '')
('*', 'fourth', '')
('*', 'fifth', '')
忽略下面的横线文本,这些文本会在单词前缀上匹配,例如。
*firstperson*
会变成
*1stperson*
P、 你最好的选择是分裂和重新加入美国。无论如何,这很可能是re.sub在幕后所做的,因为字符串是不可变的。
要解决此问题,只能在关键字前面的分隔符上进行匹配
或
或
字符串的结尾)。
def replace_words(string, rep_dict, separator):
regex = r'(^|{0})({1})'.format(
re.escape(separator), '|'.join(rep_dict.keys())
)
return re.sub(
regex, lambda x: print(x.groups()) or '{0}{1}'.
format(x.group(1), rep_dict[x.group(2)]), string
)