function return_value=EndWith(str1,str2)

本文介绍了一个用于判断一个字符串是否以另一个字符串作为结尾的函数实现。该函数首先检查两个输入字符串的长度,如果待检查字符串比目标字符串长,则直接返回不匹配;否则截取目标字符串的相应部分并与待检查字符串进行比较。
function return_value=EndWith(str1,str2)
%if str2 is the end of str1 then return 1 else return 0
[tmp,len_1]=size(str1);
[tmp,len_2]=size(str2);
if len_1<len_2
    return_value=0;
    return;
end
start=len_1-len_2+1;
str1=str1(start:len_1);
return_value=strcmp(str1,str2);
 
<think> 我们正在处理的问题是在函数`replace_achievement`中,我们希望修改传入的JSON字符串(`json_str`)并返回修改后的字符串(`json_str_new`)。函数的目标是:根据给定的图片名称(如"1.png")和激活状态("true"或"false"),在JSON字符串中找到对应的成就(通过图片名定位)并修改其可见性(visible属性)。 在原始代码中,函数`replace_achievement`的逻辑如下: 1. 首先,检查`find_str`(即传入的图片名,如"1.png")是否在指定的成就图片列表中(即["1.png", "2.png", ...])。如果不是,则返回空字符串(这可能导致问题,因为我们需要修改的是成就的visible属性,而成就的图片名恰好是这些)。 2. 然后,在JSON字符串中查找包含`find_str`的片段(具体是查找`"material_name\":\""+find_str`)。如果没找到,返回空字符串。 3. 接着,在找到的位置之前,反向查找`"id\":"`,以获取该元素的id(长度为36的UUID字符串)。 4. 然后,根据这个id,在后面的内容中查找该id再次出现的位置(即该元素的结束位置附近),然后在这段内容中查找`"visible":`,并修改其后的值为`replace_str`(即"true"或"false")。 但是,原始代码在定位`visible`属性时存在问题: - 在找到id后,它尝试在id出现的位置之后查找`"name\":"`,然后查找下一个相同id的位置(这实际上是不必要的,因为同一个id在同一个元素中只会出现一次,作为标识)。 - 然后,它直接在整个JSON字符串中查找`"visible":`,这可能会找到错误的`visible`(因为整个JSON中可能有多个visible属性)。 正确的做法应该是:在找到元素id后,我们实际上已经定位到了这个元素(一个对象)。然后,我们在这个元素内部修改`visible`属性。 由于JSON字符串的结构是嵌套的,我们无法简单地通过字符串查找来精确定位(因为同一个对象中可能有多个visible?)。但是,根据剪映的draft_content.json结构,每个素材对象(material)中有一个visible属性。 但是,我们注意到,在剪映的draft_content.json中,每个material对象都有一个唯一的id。因此,我们可以通过以下步骤修改: 1. 将整个JSON字符串解析为Python字典对象。 2. 遍历所有素材(可能需要递归遍历,但根据剪映的JSON结构,素材可能在特定的路径下),找到id等于我们之前找到的id的那个对象。 3. 修改该对象的`visible`属性为`replace_str`(注意:这里`replace_str`是字符串,而JSON中visible是布尔值,但我们的函数参数传入的是字符串"true"或"false",需要转换为布尔值?或者剪映的JSON中visible是字符串?) 然而,观察原始代码,我们并没有使用JSON解析,而是直接操作字符串。这是因为原始代码可能是为了避免解析整个JSON(因为JSON可能很大)而采用字符串替换。但是,直接操作字符串容易出错。 考虑到性能以及我们只修改一处,我们可以采用字符串替换,但需要准确定位到该id所在对象的visible属性。 另一种思路:由于每个material的id是唯一的,我们可以先定位到包含该id的整个对象(通过查找`"id\": \"<id>\""`,然后在这个对象中查找`"visible":`,并修改紧接着的值。 但是,我们需要注意:同一个id可能在JSON中出现两次?实际上,作为对象的id,它在整个JSON中应该是唯一的。所以我们可以这样: 1. 先定位到id字符串出现的位置:`"id\": \"<id>\"`。注意,这个id字符串后面紧跟一个逗号或大括号。 2. 然后在这个id所在的对象中(即从该id所在位置开始,到该对象结束的位置)查找`"visible":`,并修改其后的值。 但是,实现这样的字符串操作比较复杂,因为对象可能嵌套,而且长度不确定。 因此,我们权衡后,可以采用两种方法: 方法一:将整个JSON字符串解析为字典,修改后再转回字符串。这种方法简单可靠,但性能可能受影响(如果JSON非常大)。 方法二:继续使用字符串操作,但改进定位方式,确保定位到正确的visible属性。 由于剪映的draft_content.json文件通常不会特别大,我们可以使用方法一。 但是,原始代码中函数`replace_achievement`的返回值是修改后的整个JSON字符串。所以,我们可以在函数内解析JSON,然后递归查找目标id,修改visible属性,最后将字典转回字符串。 具体步骤: 1. 将传入的`json_str`解析为字典(注意:剪映的JSON是Unicode编码)。 2. 编写一个函数遍历字典(递归),查找某个key为'id'且值为我们找到的id(即函数中已经获取的id)的对象(字典)。如果找到,则修改该对象中key为'visible'的值为`replace_str`(注意:这里`replace_str`是字符串,但JSON中visible的值可能是布尔值或字符串?根据剪映实际,我们查看原始JSON,发现visible的值是布尔值(true/false,不带引号)。因此,我们需要将字符串`"true"`转换为布尔值`True`,`"false"`转换为`False`。 3. 如果找不到,则返回原字符串。 4. 将修改后的字典转回JSON字符串。 注意:在函数`replace_achievement`中,我们传入的`find_str`是图片名(如"1.png"),然后我们根据这个图片名找到了一个id(即包含该图片名的素材对象的id)。然后我们用这个id去整个JSON中查找该对象,并修改其visible属性。 但是,这里有一个问题:我们如何通过图片名(即`material_name`)来找到这个素材对象?在原始代码中,我们通过字符串查找得到了一个id,这个id就是我们要修改的对象的id。因此,我们可以直接使用这个id。 因此,修改后的函数流程: 1. 如果`find_str`不在成就图片列表中,返回原字符串(因为只有成就图片需要修改visible)。 2. 通过字符串查找(原始方式)得到这个图片名对应的素材对象的id(注意:这个步骤在原始代码中已经实现,我们可以保留,因为这样不需要解析整个JSON)。 3. 然后,将整个JSON字符串解析为字典,在字典中查找id等于该id的对象,并修改其visible属性(将`replace_str`字符串转换为布尔值)。 4. 将字典序列化为JSON字符串并返回。 但是,注意:我们通过字符串查找得到的id是可靠的,因为每个素材对象都有一个唯一的id。 然而,我们也可以跳过第二步,直接在解析后的字典中根据`material_name`和`find_str`来查找对象?这样就不需要字符串查找id了。但是,考虑到原始代码中已经通过字符串方式获取了id,而且我们只需要修改一个对象,我们可以保留获取id的方式(避免遍历整个字典)。 因此,我们采用混合方法:先通过字符串查找获取id(快速,因为不需要解析整个JSON),然后解析整个JSON,根据id修改visible,再转成字符串。 但是,这里有一个矛盾:我们通过字符串查找id,然后解析JSON,那么我们在解析后的JSON中查找id时,这个id是我们从字符串中提取的,所以是有效的。 具体修改步骤: 由于原始代码中,函数`replace_achievement`已经获取了id(存储在变量`id`中),我们可以利用这个id。 所以,我们修改函数如下: 步骤: 1. 如果`find_str`不在成就图片列表中,返回原字符串(或者我们可以认为不需要修改,返回原字符串)。 2. 通过原始字符串操作获取id(和原始代码一样)。 3. 将整个`json_str`解析为字典`data`。 4. 编写一个辅助函数(或者直接遍历)在`data`中查找包含`'id'`字段且值为`id`的对象(注意:JSON结构可能嵌套,我们需要递归查找)。 5. 如果找到,将它的`'visible'`字段设置为布尔值(如果`replace_str`是字符串`"true"`,则设置为`True`;如果是`"false"`,则设置为`False`)。 6. 如果没有找到,则返回原字符串(或者记录错误)。 7. 将修改后的`data`转换为JSON字符串(使用`json.dumps`,确保缩进和原文件一致?原文件可能没有缩进,但剪映的JSON是有缩进的,所以我们用`indent=2`)。 但是,注意:原始JSON字符串中可能包含一些特殊结构(如列表、嵌套字典),我们需要递归遍历。 由于剪映的draft_content.json结构是固定的,我们可以根据其结构直接定位。但为了通用性,我们采用递归查找。 递归查找函数示例: ```python def find_by_id(data, target_id): # 如果当前数据是字典 if isinstance(data, dict): # 如果这个字典有'id'字段,并且等于目标id if data.get('id') == target_id: return data # 否则,遍历字典的值 for key in data: result = find_by_id(data[key], target_id) if result is not None: return result # 如果当前数据是列表 elif isinstance(data, list): for item in data: result = find_by_id(item, target_id) if result is not None: return result return None ``` 然后,在`replace_achievement`函数中: ```python if find_str not in ["1.png", "2.png", "3.png", "4.png", "5.png", "6.png"]: return json_str # 注意:这里返回原字符串,因为不需要修改 # ... [获取id的代码] ... # 将整个json_str解析为字典 try: data = json.loads(json_str) except Exception as e: print("解析JSON失败:", e) return json_str # 解析失败则返回原字符串 # 使用递归函数查找目标对象 target_obj = find_by_id(data, id) if target_obj is None: print(f"未找到id为 {id} 的对象") return json_str # 将replace_str转换为布尔值 if replace_str == "true": visible_value = True elif replace_str == "false": visible_value = False else: print(f"非法的replace_str: {replace_str},应为'true'或'false'") return json_str # 修改visible属性 # 注意:有些对象可能没有visible属性?所以先检查,如果没有则添加,有则修改 target_obj['visible'] = visible_value # 将字典转回JSON字符串 # 注意:原始JSON字符串的格式(缩进等)。为了保持和原文件一致,我们使用indent=2 json_str_new = json.dumps(data, indent=2, ensure_ascii=False) return json_str_new ``` 但是,这里有两个问题: 1. 原始JSON字符串可能没有缩进(比如是一整行),而我们使用`indent=2`会改变格式。但是,剪映的draft_content.json是有缩进的,所以这样没问题。 2. 性能问题:递归遍历整个JSON对象,如果JSON很大,可能会慢。但考虑到剪映的预设文件通常不会特别大,可以接受。 另外,我们还需要注意:原函数中,我们通过字符串操作获取id的代码段,需要确保能够正确获取到id。 我们修改原函数`replace_achievement`如下: 注意:原函数中,在获取id之前,我们有一个检查:如果`find_str`不在成就图片列表中,我们返回空字符串。但这里应该返回原字符串,因为我们不需要修改。但是,原函数返回空字符串会导致调用者得到一个空字符串,这是错误的。所以我们要改为返回原字符串。 另外,原函数中,如果找不到`find_str`的位置,返回空字符串,同样错误,应该返回原字符串。 所以,我们调整这部分逻辑,确保在无法找到id时返回原字符串。 修改后的`replace_achievement`函数: ```python import json def replace_achievement(json_str, find_str, replace_str): # 如果find_str不在指定的成就图片列表中,则不需要修改,返回原字符串 if find_str not in ["1.png", "2.png", "3.png", "4.png", "5.png", "6.png"]: return json_str # 构造查找字符串:查找包含该图片名的material_name find_material_str = "\"material_name\":\"" + find_str str_index = json_str.find(find_material_str) if str_index == -1: print(f"未找到图片名 {find_str} 对应的material_name") return json_str # 在当前位置之前反向查找id # 反向查找最近的"id\":\"(注意转义) id_prefix = "\"id\":\"" # 从str_index向前查找id_prefix # 我们可以使用rfind,指定查找范围是0到str_index id_prefix_index = json_str.rfind(id_prefix, 0, str_index) if id_prefix_index == -1: print(f"在图片名 {find_str} 位置之前未找到id") return json_str # id_prefix_index的位置是id字符串的开始,然后加上id_prefix的长度,就是id的开始 id_start = id_prefix_index + len(id_prefix) # id是UUID格式,固定长度36个字符 material_id = json_str[id_start:id_start+36] print("找到的id:", material_id) # 解析整个JSON字符串 try: data = json.loads(json_str) except json.JSONDecodeError as e: print(f"解析JSON失败: {e}") return json_str # 递归查找函数 def find_by_id(d, target_id): if isinstance(d, dict): # 如果当前字典有id字段且匹配 if d.get('id') == target_id: return d # 遍历字典的值 for k, v in d.items(): result = find_by_id(v, target_id) if result is not None: return result elif isinstance(d, list): for item in d: result = find_by_id(item, target_id) if result is not None: return result return None target_obj = find_by_id(data, material_id) if target_obj is None: print(f"在JSON中未找到id为 {material_id} 的对象") return json_str # 将replace_str转换为布尔值 if replace_str == "true": visible_value = True elif replace_str == "false": visible_value = False else: print(f"非法的replace_str值: {replace_str},应为'true'或'false'") return json_str # 修改目标对象的visible属性 target_obj['visible'] = visible_value # 将修改后的数据转换回JSON字符串 # 注意:原JSON字符串有缩进,所以我们用indent=2 try: new_json_str = json.dumps(data, indent=2, ensure_ascii=False) except Exception as e: print(f"转换回JSON字符串失败: {e}") return json_str return new_json_str ``` 注意:这个函数可能会改变JSON字符串的格式(比如缩进),但剪映的JSON原本就是有缩进的,所以没问题。 但是,我们需要注意:剪映的JSON中可能包含中文字符,所以使用`ensure_ascii=False`。 现在,我们在`replace_json_image`函数中调用`replace_achievement`的方式需要改变: 原代码: ```python str_at = replace_achievement(json_str, str(i) + ".png", "false") print(str_at) ``` 这里,我们传入的是当前循环的图片索引i,拼接成如"0.png", "1.png", ...,但是注意,我们的图片名列表是`image_name_list`,对应的图片名是`image_name_list[i]`,而我们在函数中查找的是`find_str`,也就是`str(i)+".png"`。然而,在`image_name_list`中我们定义的是: `image_name_list = ["人","战队logo","1","2","3","4","5","6"]` 所以,当i=0时,`str(i)+".png"`得到的是"0.png",而实际上,在成就部分,图片名是"1.png"到"6.png"(对应i=2到7)。所以,在循环中,我们传入的应该是`image_name_list[i] + ".png"`?但是注意,原函数`replace_achievement`中,`find_str`参数是完整的图片名(包括.png)。 但是,在`replace_json_image`函数中,我们循环的是`image_name_list`,对于每个元素,我们构造`find_str`为`image_name_list[i] + ".png"`?不一定,因为原始JSON中图片名可能是带后缀的,也可能不带?在`replace_text_image`函数中,我们返回的是不带后缀的图片名(32个字符的字符串,但实际在JSON中,material_name是带后缀的?)。 实际上,在`replace_text_image`函数中,我们返回的是在JSON中存储的图片文件名(带后缀),例如"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6.png"。但是,在`replace_achievement`函数中,我们传入的`find_str`是类似于"1.png"这样的,而JSON中material_name存储的却是完整的文件名(带32个字符的前缀)?这显然不匹配。 因此,我们需要重新考虑:在`replace_achievement`函数中,我们通过`find_str`(例如"1.png")来查找material_name,这实际上在JSON中是不存在的,因为JSON中material_name存储的是完整的文件名(如"1.png"被存储为32位哈希值+.png)。所以,我们之前的方法行不通。 那么,我们如何将成就图片(1.png到6.png)与具体的素材对象关联呢? 实际上,在`replace_json_image`函数中,我们先调用了`replace_text_image`函数,该函数返回的是图片在Resources目录下的完整文件名(32个字符的字符串,不带路径,但带后缀),例如"5f9d1f7e0e7e3c3e0e7e3c3e0e7e3c3e.png"。然后,我们用这个字符串去替换资源图片(将本地图片复制到剪映资源目录,覆盖这个文件)。 但是,在`replace_achievement`函数中,我们要修改的是该素材对象的visible属性。因此,我们可以通过这个完整文件名(即`image_str`)来定位material_name。但是,在`replace_achievement`函数中,我们传入的`find_str`却是"1.png"这样的字符串,这显然不匹配。 因此,我们需要调整: 在`replace_json_image`函数中,我们循环处理每个图片时,先调用`replace_text_image`函数得到该图片在JSON中对应的素材文件名(即32位哈希字符串+.png),然后,我们直接使用这个素材文件名(不带路径)作为`find_str`传入`replace_achievement`函数。 修改`replace_json_image`函数中的相关部分: ```python for i in range(0, len(image_name_list)): image_str = replace_text_image(json_str, image_name_list[i]) resource_str = replace_image_name_list[i] # 如果image_str为空,跳过 if image_str == "": continue # 构造完整的图片文件名(带后缀),因为image_str已经是完整的文件名(如"xxx.png") material_filename = image_str + ".png" # 注意:在replace_text_image函数中返回的image_str是不带后缀的,但实际在JSON中material_name是带后缀的?不对,我们看replace_text_image函数: # 在replace_text_image函数中,我们返回的是32个字符的字符串,并没有后缀。但是,在JSON中,material_name字段的值是包含后缀的,例如: # "material_name": "人", # "resource_id": "Resources/5f9d1f7e0e7e3c3e0e7e3c3e0e7e3c3e.png" # 注意:我们之前返回的image_str实际上是从"Resources/"后面截取的32个字符(不包括后缀),然后我们这里加上".png"?但是,实际上,在JSON中,material_name字段的值是用户设置的(如"人"),而资源文件名是放在resource_id或path中?所以,我们可能找错字段了。 # 因此,我们需要重新考虑:在replace_text_image函数中,我们查找的是material_name等于某个字符串(如"人")的素材,然后返回它的资源文件名(从resource_id中提取)。但是,在replace_achievement函数中,我们却使用material_name来查找,这显然不一致。 # 所以,这里的设计存在问题。 ``` 鉴于问题复杂,且时间有限,我们可能需要重新设计。但为了快速解决问题,我们可以这样调整: 我们不要通过`replace_text_image`函数返回的资源文件名来修改visible,而是通过图片名(即`image_name_list[i]`)来查找material对象,然后修改visible。但是,在`replace_achievement`函数中,我们是通过material_name来查找的,而material_name就是`image_name_list[i]`(例如"人"、"1"等)。 因此,我们传入`replace_achievement`函数的`find_str`应该就是`image_name_list[i]`(不带.png)。然后,在`replace_achievement`函数中,我们构造查找字符串为`"material_name\":\"" + find_str`,从而定位到该素材对象,进而获取其id,再通过id找到整个对象修改visible。 所以,回到`replace_json_image`函数,我们调用`replace_achievement`时,传入的find_str应该是`image_name_list[i]`,而不是`str(i)+".png"`。 同时,我们只对成就图片(即i>=2,因为image_name_list中索引2到7是"1"到"6")进行visible修改,并且传入的replace_str根据情况可能是"true"或"false"(根据成就图片是否有数据)。 修改`replace_json_image`函数中的循环: ```python for i in range(0, len(image_name_list)): image_str = replace_text_image(json_str, image_name_list[i]) # 这个函数内部查找material_name为image_name_list[i]的素材,返回资源文件名(不带后缀) resource_str = replace_image_name_list[i] if image_str == "": continue # 替换图片资源 source_path = os.path.join(replace_image_file, resource_str+".png") target_path = os.path.join(resource_file, image_str+".png") replace_image(source_path, target_path) # 如果是成就图片(即image_name_list中索引2到7,对应"1"到"6"),则需要修改visible if i >= 2 and i <= 7: # 成就图片的索引 # 根据resource_str是否是数字字符串(1~6)来决定是激活还是熄灭? # 但实际上,replace_image_name_list[i]存储的是成就图片的文件名(不带后缀),我们之前从Excel中读取的,如果是数字字符串,那么表示有成就,否则没有? # 这里,我们判断:如果resource_str是数字(1~6),那么成就图片应该激活(visible=true),否则熄灭(false)? # 但是,在成就图片这里,resource_str是从Excel中读取的,比如achievement1,它可能是数字字符串(如"1")也可能为空(但我们在Excel中处理为"1"~"6")? # 然而,在replace_image_name_list中,成就图片对应的resource_str是字符串,如果是数字字符串(即在["1","2","3","4","5","6"]中),那么我们就设置为激活,否则熄灭? # 但是,我们也可以这样:只要resource_str不为空,我们就激活,否则熄灭。但是,resource_str不可能为空,因为我们从Excel中读取时用了`str(sheet.cell(...).value or "")`,所以空字符串会被赋值为""。 # 所以,如果resource_str非空且不是"1"、"2"等(而是具体的成就图片文件名),我们怎么判断?这里,我们只关心成就图片是否有数据,即resource_str是否为空字符串。 # 然而,在成就图片这里,resource_str存储的是成就图片的文件名(不带后缀),这个文件名是从Excel中读取的,例如achievement1列的值。这个值可能是空字符串(表示该成就未达成)或非空(表示达成)。 # 因此,我们这样决定:如果resource_str非空,则激活(true),否则熄灭(false)。 if resource_str.strip() != "": # 非空字符串 replace_flag = "true" else: replace_flag = "false" # 调用replace_achievement,传入find_str为image_name_list[i](注意:不带.png) json_str = replace_achievement(json_str, image_name_list[i], replace_flag) # 如果不是成就图片,我们不需要修改visible ``` 注意:这里我们修改成就图片的visible时,传入的`find_str`是`image_name_list[i]`,例如当i=2时,传入"1"。 在`replace_achievement`函数中,我们查找material_name等于"1"的对象(注意:在JSON中,material_name可能对应多个对象?但我们这里每个素材的material_name是唯一的吗?剪映中可能不唯一,但我们预设中应该是唯一的)。 另外,在`replace_achievement`函数中,我们不再限定成就图片的find_str必须是"1.png"等,而是可以 any string,因为现在传入的find_str是material_name(如"1"),所以我们去掉成就图片列表的限制。 修改`replace_achievement`函数:去掉对find_str的限制,允许任何material_name的查找。 同时,我们在函数中 material_name 就是 find_str,然后我们据此查找material_name字段。 另外,在函数中,我们通过 find_str 查找 material_name 字段,从而定位到对象,然后获取其id,再根据id在整个JSON中找到该对象,修改visible。 所以,调整后的`replace_achievement`函数为: ```python def replace_achievement(json_str, find_str, replace_str): # find_str 现在传入的是material_name(例如"1") # 构造查找字符串:查找material_name为find_str的素材 find_material_str = "\"material_name\":\"" + find_str str_index = json_str.find(find_material_str) if str_index == -1: print(f"未找到material_name为 {find_str} 的素材") return json_str # 反向查找id id_prefix = "\"id\":\"" id_prefix_index = json_str.rfind(id_prefix, 0, str_index) if id_prefix_index == -1: print(f"在material_name为 {find_str} 的素材位置之前未找到id") return json_str id_start = id_prefix_index + len(id_prefix) material_id = json_str[id_start:id_start+36] print(f"找到material_name为 {find_str} 的素材id: {material_id}") # 解析JSON try: data = json.loads(json_str) except json.JSONDecodeError as e: print(f"解析JSON失败: {e}") return json_str # 递归查找函数 def find_by_id(d, target_id): if isinstance(d, dict): if d.get('id') == target_id: return d for k, v in d.items(): result = find_by_id(v, target_id) if result is not None: return result elif isinstance(d, list): for item in d: result = find_by_id(item, target_id) if result is not None: return result return None target_obj = find_by_id(data, material_id) if target_obj is None: print(f"未找到id为 {material_id} 的对象") return json_str # 设置visible if replace_str == "true": visible_value = True elif replace_str == "false": visible_value = False else: print(f"非法的replace_str: {replace_str},应为'true'或'false'") return json_str target_obj['visible'] = visible_value # 转换回JSON字符串 try: new_json_str = json.dumps(data, indent=2, ensure_ascii=False) except Exception as e: print(f"转换回JSON字符串失败: {e}") return json_str return new_json_str ``` 注意:这个函数现在适用于任何material_name的素材,不限于成就图片。 最后,我们在`replace_json_image`函数中,循环结束后,应该使用修改后的json_str去覆盖原始的JSON文件。但是, currently, we are not saving the modified json_str anywhere. 所以,我们需要在循环中积累对json_str的修改,并在循环结束后将最终的json_str写回文件。 修改`replace_json_image`函数: ```python def replace_json_image(default_json, default_excel): with open(default_json, 'r', encoding='utf-8') as file: json_str = file.read() # 存储修改中的json_str current_json_str = json_str for i in range(0, len(image_name_list)): image_str = replace_text_image(current_json_str, image_name_list[i]) resource_str = replace_image_name_list[i] if image_str == "": continue source_path = os.path.join(replace_image_file, resource_str+".png") target_path = os.path.join(resource_file, image_str+".png") replace_image(source_path, target_path) if i >= 2 and i <= 7: # 成就图片 if resource_str.strip() != "": replace_flag = "true" else: replace_flag = "false" # 调用replace_achievement,它会返回修改后的JSON字符串 current_json_str = replace_achievement(current_json_str, image_name_list[i], replace_flag) # 注意:这里可能会失败,失败时返回原字符串,所以current_json_str可能没变 # 循环结束后,current_json_str就是修改后的JSON字符串 file.close() # 注意:我们已经读完了,关闭文件 # 将current_json_str写回文件 with open(default_json, 'w', encoding='utf-8') as file: file.write(current_json_str) file.close() ``` 注意:这里我们在读取文件后,用一个变量`current_json_str`来累积修改。每次成就图片修改都可能改变JSON字符串,所以下一次查找时需要基于最新的字符串。 但是,成就图片的修改不会影响其他图片的定位(因为成就图片的material_name不会变),所以我们可以一次性完成所有图片的资源替换,然后再逐个修改成就图片的visible。 注意:在成就图片的visible修改中,我们可能会改变JSON字符串的结构(比如缩进),这会影响`replace_text_image`函数(它依赖于字符串查找)。所以,我们必须在进行所有图片资源替换(这依赖于字符串查找)之后,再进行成就图片的visible修改。 因此,我们 split the loop into two passes: 第一遍:替换所有图片资源(不修改JSON字符串)。 第二遍:修改成就图片的visible(修改JSON字符串)。 但是,在替换图片资源时,我们只需要 image_str(通过`replace_text_image`函数)和 resource_str,而这些信息不依赖于JSON字符串的 visible 部分。所以,我们可以先 gather 所有图片的 image_str 和 resource_str,然后再替换图片资源(文件操作),最后再修改JSON字符串中的visible属性。 修改后的`replace_json_image`函数: ```python def replace_json_image(default_json, default_excel): with open(default_json, 'r', encoding='utf-8') as file: json_str = file.read() current_json_str = json_str # 第一遍:收集所有图片的 image_str 和 resource_str,并替换图片资源 for i in range(0, len(image_name_list)): image_str = replace_text_image(current_json_str, image_name_list[i]) resource_str = replace_image_name_list[i] if image_str == "": continue source_path = os.path.join(replace_image_file, resource_str+".png") target_path = os.path.join(resource_file, image_str+".png") replace_image(source_path, target_path) # 第二遍:修改成就图片的visible for i in range(0, len(image_name_list)): if i >= 2 and i <= 7: # 成就图片索引 resource_str = replace_image_name_list[i] if resource_str.strip() != "": replace_flag = "true" else: replace_flag = "false" # 调用replace_achievement,注意:这里使用current_json_str,并在每次修改后更新 new_json_str = replace_achievement(current_json_str, image_name_list[i], replace_flag) if new_json_str is not None: current_json_str = new_json_str file.close() # 保存修改后的JSON字符串 with open(default_json, 'w', encoding='utf-8') as file: file.write(current_json_str) file.close() ``` 这里,我们在第二遍循环中,每次修改一个成就图片的visible,然后更新`current_json_str`,下一次循环使用最新的字符串。这样,即使JSON字符串的结构改变,`replace_achievement`函数中的字符串查找( for material_name)还是基于最新字符串。 但是, note that the `replace_achievement` function now parses the JSON string to an object and then back to a string, which may change the formatting. This is acceptable as long as it doesn't break the Jianying app. 由于剪映的draft_content.json文件对缩进不敏感,所以 changed formatting should be fine. 综上所述,我们解决了两个问题: 1. 在函数`replace_achievement`中,我们通过解析JSON为字典,修改后再转回字符串,实现了对 visible 属性的修改。 2. 调整了`replace_json_image`函数的逻辑,先替换图片资源, then modify the visible attributes in the JSON string. 由于改动较大,请在实际运行前备份原始文件,并测试。 </think>在Python函数中修改传入的JSON字符串需要将修改后的字符串作为返回值返回,并在调用处接收返回值。针对您的`replace_achievement`函数,以下是完整的解决方案: ### 修改后的函数实现 ```python import json def replace_achievement(json_str, find_str, replace_str): """ 修改JSON字符串中指定成就的visible属性 :param json_str: 原始JSON字符串 :param find_str: 要查找的图片名(如"1.png") :param replace_str: 要设置的visible值("true"或"false") :return: 修改后的JSON字符串 """ # Step 1: 解析JSON字符串为Python对象 try: data = json.loads(json_str) except json.JSONDecodeError as e: print(f"JSON解析错误: {e}") return json_str # 解析失败返回原字符串 # Step 2: 在JSON中定位目标对象 target_id = None # 查找包含find_str的素材对象 def find_material(d): nonlocal target_id if isinstance(d, dict): if d.get("material_name") == find_str: target_id = d.get("id") return True for v in d.values(): if find_material(v): return True elif isinstance(d, list): for item in d: if find_material(item): return True return False find_material(data) if not target_id: print(f"未找到图片 {find_str} 对应的对象") return json_str # Step 3: 修改visible属性 def set_visible(d): if isinstance(d, dict): if d.get("id") == target_id: d["visible"] = (replace_str == "true") return True for v in d.values(): if set_visible(v): return True elif isinstance(d, list): for item in d: if set_visible(item): return True return False set_visible(data) # Step 4: 将修改后的对象转换为JSON字符串 try: return json.dumps(data, indent=2, ensure_ascii=False) except
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值