Python 更新字符串替换以忽略列表中的值
我试图替换字符串中的子字符串,条件是被替换的值不在忽略列表中。例如,由于id_1位于忽略列表中,因此不应替换测试_str中的“id_1”:Python 更新字符串替换以忽略列表中的值,python,Python,我试图替换字符串中的子字符串,条件是被替换的值不在忽略列表中。例如,由于id_1位于忽略列表中,因此不应替换测试_str中的“id_1”: ignore_list = ['id_1'] test_str = "id_1Testid" test_str = test_str.replace('id' , 'test2') test\u str应包含“id\u 1Testtest2”而不是“test2\u 1test2” 如何更新以使ignore_list中test_str中的
ignore_list = ['id_1']
test_str = "id_1Testid"
test_str = test_str.replace('id' , 'test2')
test\u str
应包含“id\u 1Testtest2
”而不是“test2\u 1test2
”
如何更新以使ignore_list
中test_str
中的项目不被替换?您可以先将“id_1”替换为“#”(例如),然后再添加它:
ignore_list = ['id_1']
test_str = "id_1Testid"
replace_str = "id"
test_str = test_str.replace(ignore_list[0], "#")
test_str = test_str.replace(replace_str, "test2")
test_str = test_str.replace("#", ignore_list[0])
print(test_str)
您可以构建一个regexp来使用以下命令搜索:
def specialReplace(字符串、searchStr、replaceStr、ignoreList):
#创建一个regexp搜索所有不在ignoreList中的id,这要归功于负前瞻。
searchedRegexp=re.escape(searchStr)
ignoredPatternRegexp='|'。join([k的重新转义(k)表示k在排序中(ignoreList,key=len,reverse=True)])
pattern=re.compile(f'(?!({ignoredPatternRegexp})){searchedRegexp},flags=re.DOTALL)
#做实际的更换工作
返回模式.sub(replaceStr,string)
打印(特殊替换(“id\u 1Testid”、“id”、“test2”、“id\u 1]”)
输出:
id_1Testtest2
id_1id_2Testtest2_test2_test2
aaidaaTesttest2
aaidaaaaidbbTesttest2bytest2by
id_1test2
不是单行线,但它可以:
重新导入
定义my_replacer(忽略_列表,输入_str,替换,替换为):
忽略索引=[(m.start(),m.end())在忽略列表中为w在re.finditer(w,input_str)中为m)
temp=[(m.start(),m.end())表示re.finditer中的m(要替换,请输入)]
替换_索引=[]
对于临时工:
rep_i=真
对于忽略指数中的j:
如果j[0]不是很好,但这似乎有效:
import re
def complex_replace(subject, ignore_lst, txt_to_replace, replacement_txt):
ignore_pattern = '|'.join([re.escape(ignore_lst[i]) for i in range(len(ignore_lst))])
str_idxs = [idx for tu in re.finditer(ignore_pattern, subject) for idx in tu.span()]
split_str = [
(subject[str_idxs[i]:str_idxs[i+1]], 'U' if i % 2 == 0 else 'M')
for i in range(len(str_idxs) - 1)
]
split_str.append((subject[str_idxs[-1]:len(subject)], 'M'))
res = ''.join(
[
substr[0].replace(txt_to_replace, replacement_txt)
if substr[1] == 'M' else substr[0] for substr in split_str
]
)
return res
其作用如下:
构建一个带有忽略列表的正则表达式模式(忽略列表中的项目用|
构建一个索引列表,标记与忽略列表中的项匹配的主题字符串的子字符串的开始和结束
构建一个子字符串列表,其中每个列表项都由一个带有子字符串的元组和一个标记子字符串为不可变('U')或可变('M')的标志组成。将主题字符串的结尾(从步骤2中找到的最后一个索引到主题字符串的结尾)添加到该子字符串列表中
根据3中构建的子字符串列表中的元组,使用连接和列表理解进行替换:仅当子字符串标记为可变('M')时才进行替换,否则('U'),将子字符串保持不变
以下测试:
ignore_list = ['id_1']
test_str = "id_1Testid"
to_replace = 'id'
replacement = 'test2'
print(complex_replace(test_str, ignore_list, to_replace, replacement))
ignore_list = ['test', 'blah']
test_str = 'test blah testbidtest bitest testblue'
to_replace = 'bi'
replacement = 'tooTooT'
print(complex_replace(test_str, ignore_list, to_replace, replacement))
ignore_list = ['id_1', 'id_2']
test_str = "id_1id_2Testid_id_id"
to_replace = 'id'
replacement = 'test2'
print(complex_replace(test_str, ignore_list, to_replace, replacement))
ignore_list = ['aaidaa']
test_str = "aaidaaTestid"
to_replace = 'id'
replacement = 'test2'
print(complex_replace(test_str, ignore_list, to_replace, replacement))
ignore_list = ['aaidaa', 'aaidbb']
test_str = "aaidaaaaidbbTestidbyidby"
to_replace = 'id'
replacement = 'test2'
print(complex_replace(test_str, ignore_list, to_replace, replacement))
给出以下输出:
id_1Testtest2
test blah testtooTooTdtest tooTooTtest testblue
id_1id_2Testtest2_test2_test2
aaidaaTesttest2
aaidaaaaidbbTesttest2bytest2by
使用,查找所需和不需要的匹配项,并仅替换所需的匹配项:
import re
def complex_replace(subject, ignore_lst, txt_to_replace, replacement_txt):
return re.sub('|'.join(map(re.escape, ignore_lst + [txt_to_replace])),
lambda match: match.group()
if match.group() in ignore_lst else
replacement_txt,
subject)
所有测试用例的结果都与的解决方案相同。这是一个非常好的挑战:d我能想到的唯一方法是,如果您使用正则表达式形式replace
,并且您可以在该表达式中包含一个字符串列表。如果您进行扩展,这似乎是完全可行的将列表转换为表达式字符串。Stackoverflow不是免费的编码服务。您需要诚实地尝试解决方案,然后询问有关该解决方案的具体问题(如有必要)。您能否澄清“被替换的值不在忽略列表中”是什么意思。是否应在发现id
的位置检查忽略列表中的项目?如果前后都不可能?您对test\u str=“abababidab\u ababidab\u abidab\u idididid”
和忽略列表=[“ababidab”、“2id”、“idt”]的预期结果是什么
。此输入有一个独特的解决方案,使我们能够轻松区分正确答案和错误答案。@blue sky接受的答案似乎并不适用于所有情况,例如打印(复杂的替换(“id\U id\U 1Testid”、['id\U 1']、'id'、'test2'))
。但是如果#
出现在test\u str
中的某个地方怎么办?是的,公平的说,也许你必须使用一些更特殊的东西,比如~
等等……但这应该是它的工作逻辑。你需要做的是首先逃避你作为替代品使用的任何东西,然后让你的逻辑足够聪明,不还原代码替换的ed版本,但只是取消替换。-我想,一旦知道传入字符串数据的域,您的解决方案就可以按原样工作。如果您知道替换将永远不会出现在传入数据中,那么这将是很好的。您可以做的一件事是使替换更加模糊,如~~###$#@代码>:)这似乎不能正常工作。尝试在测试调用的两个位置将id_1
更改为aaidaa
。我很好奇为什么这是…为什么它适用于一个词而不是另一个词。我一直在玩这个。只有当要替换的字符串出现在ignore\u list
@CryptoFool中每个单词的开头时,您的解决方案才有效。您的意思是specialReplace(“aaidatestid”、“id”、“test2”、“aaidaa”)
?它给出了'aatest2atesttest2'
。这对我来说似乎是正确的:第一个被替换,因为aaida
在之前启动。第二个不在忽略列表中。这似乎符合OP的要求,尽管这一点在问题中不是很清楚……是的,这就是我的意思。“开始之前”是什么意思?第一个在忽略列表中,那么为什么替换它可以呢?答案不应该是aaidatetest2
?我看不出OPs问题是如何排除这种情况的。我理解这个问题是:在字符串中搜索id
,如果在这个位置找到它的任何项目,不要替换它(因此不是在前面,也不是在后面)。