使用正则表达式检查以下代码:
import re
# set up the regex pattern
# the words which should be skipped, must be whole word and case-insensitive
ptn_to_skip = re.compile(r'\b(?:no|none)\b', re.IGNORECASE)
# the pattern for mapping
# Note: any regex meta charaters need to be escaped, or it will fail.
ptn_to_map = re.compile(r'\b(' + '|'.join(replace_terms_df.Text.tolist()) + r')\b')
# map from text to Replace_item
terms_map = replace_terms_df.set_index('Text').Replace_item
def adjust_text(x):
# if 1 - 3 ptn_to_skip found, return x,
# otherwise, map the matched group \1 with terms_map
if 0 < len(ptn_to_skip.findall(x)) <= 3:
return x
else:
return ptn_to_map.sub(lambda y: terms_map[y.group(1)], x)
# do the conversion:
text_df['new_text'] = text_df.Text.apply(adjust_text)
一些注意事项:
- 我将
replace_terms_df.Text 中的文本转换为正则表达式。默认文本都是没有正则表达式元字符的纯文本。
- 如果有任何正则表达式元字符,如'$'、']' 等,您将不得不转义它们。正则表达式往往很慢,尤其是元字符,如果您有大量数据,请不要向您推荐此解决方案。
更新:
增加了一个新的逻辑,首先检查excluded-words ['no', 'none'],如果匹配,然后找到接下来的0-3个本身不是excluded-words的单词,将它们保存到\1,实际匹配的搜索词将保存在 \2 中。然后在正则表达式替换部分,以不同的方式处理它们。
以下是新代码:
import re
# pattern to excluded words (must match whole-word and case insensitive)
ptn_to_excluded = r'\b(?i:no|none)\b'
# ptn_1 to match the excluded-words ['no', 'none'] and the following maximal 3 words which are not excluded-words
# print(ptn_1) --> \b(?i:no|none)\b\s*(?:(?!\b(?i:no|none)\b)\S+\s*){,3}
# where (?:(?!\b(?i:no|none)\b)\S+\s*) matches any words '\S+' which is not in ['no', 'none'] followed by optional white-spaces
# {,3} to specify matches up to 3 words
ptn_1 = r'{0}\s*(?:(?!{0})\S+\s*){{,3}}'.format(ptn_to_excluded)
# ptn_2 is the list of words you want to convert with your terms_map
# print(ptn_2) --> \b(?:random|here|some)\b
ptn_2 = r'\b(?:' + '|'.join(replace_terms_df.Text.tolist()) + r')\b'
# new pattern based on the alternation using ptn_1 and ptn_2
# regex: (ptn_1)|(ptn_2)
new_ptn = re.compile('({})|({})'.format(ptn_1, ptn_2))
# map from text to Replace_item
terms_map = replace_terms_df.set_index('Text').Replace_item
# regex function to do the convertion
def adjust_map(x):
return new_ptn.sub(lambda m: m.group(1) or terms_map[m.group(2)], x)
# do the conversion:
text_df['new_text'] = text_df.Text.apply(adjust_map)
说明:
我定义了两个子模式:
- ptn_1:尝试匹配你想要排除的单词,即单词'no','none'后跟最多3个不在['no','none']中的单词
- ptn_2:尝试根据 replace_terms_df 匹配您要转换的单词之一。
它是如何工作的:
- 使用替换“|”,正则表达式引擎将确保 ptn_1 在 ptn_2 之前匹配,如果两者都不匹配,则保留原始文本。
- 匹配的ptn_1文本将保存在m.group(1)中,ptn_2结果保存到m.group(2)中
- 在替换部件中。如果 m.group(1) 不是 Empty(意味着 ptn_1 匹配)则返回 m.group(1) (因此这部分匹配未触及),否则返回 terms_map[y.group(2)]
以下一些测试:
In []: print(new_ptn)
re.compile('(\\b(?i:no|none)\\b\\s*(?:(?!\\b(?i:no|none)\\b)\\S+\\s*){,3})|(\\b(random|here|some)\\b)')
In[]: for i in [
'yes, no such a random text'
, 'yes, no such a a random text'
, 'no no no such a random text no such here here here no'
]: print('{}:\n [{}]'.format(i, adjust_map(i)))
...:
yes, no such a random text:
[yes, no such a random text]
yes, no such a a random text:
[yes, no such a a <RANDOM_REPLACED> text]
no no no such a random text no such here here here no:
[no no no such a random text no such here here <HERE_REPLACED> no]
让我知道这是否有效。
更多考虑:
- 在 ptn_1 中,'\S+' 用于定义一个 WORD,如果其中一个单词是 ',none' 之类的,则会出现问题,前面的 'comma' 将让它跳过(?!\b(?:no|none)) 测试。
- 其实应该排除',no', '"none"'吗?这将影响单词的计数方式。修改
ptn_to_excluded 就足够了。