Ruby操作JSON文件时为何替换数组元素而非新增?如何直接操作文件字符串而非完整JSON结构?
解答你的两个Ruby JSON操作疑问
问题一:为什么代码会同时替换数组最后一个元素并新增重复条目?
咱们来拆解下代码里的关键逻辑:
- 你通过
lastLine = data["Role"]["AssumeRolePolicyDocument"]["Statement"][0]["Principal"]["AWS"][-1]获取了数组最后一个元素的字符串。在Ruby中,字符串是可变对象,变量lastLine并不是原字符串的副本,而是直接指向原数组中那个字符串对象的引用。 - 接下来执行的
lastLine[marker] = "user/#{user}"——这个[]=操作是直接修改了lastLine指向的原字符串内容,也就是说原数组的最后一个元素被你直接修改了。 - 最后又执行
data[...] += [lastLine],把已经修改过的这个字符串再次添加到数组末尾,自然就出现了“替换最后一个元素+新增重复条目”的结果。
简单总结:你误以为lastLine是独立的新字符串,但它和原数组的最后一个元素是同一个对象,修改它就等于修改原数组内容,之后再添加它,就会多一条重复项。
问题二:如何直接操作文件字符串而非解析JSON?
如果你不想解析整个JSON结构,可以直接把文件内容当成纯字符串处理,用正则匹配找到目标位置插入新条目。这种方法适合JSON格式相对固定的场景,下面是一个可运行的示例:
filepath = "/tmp/my/my-apply-iam-role.assume-role.json" user = "harold" # 读取整个文件为字符串 file_content = File.read(filepath) # 构造新的ARN条目(匹配原JSON的引号格式) new_arn = "arn:aws:iam::123123123123:user/#{user}" new_entry = "\"#{new_arn}\"" # 用正则匹配AWS数组,在末尾插入新条目 # /m修饰符让.可以匹配换行,适配多行数组格式 updated_content = file_content.gsub(/("AWS":\s*\[(.*?)\])/m) do inner_content = $2.strip if inner_content.empty? # 空数组的情况 "\"AWS\": [#{new_entry}]" else # 已有元素,加逗号分隔 "\"AWS\": [#{inner_content}, #{new_entry}]" end end # 将修改后的内容写回文件 File.write(filepath, updated_content)
额外提示:
直接操作字符串的方式虽然绕开了JSON解析,但对JSON格式的变动很敏感(比如缩进、换行、空格变化都可能导致正则匹配失败)。如果场景允许,解析JSON后修改其实是更稳妥的方案——只需要调整你原代码的逻辑,去掉修改原数组元素的步骤,直接构造新ARN添加:
require 'json' filepath="/tmp/my/my-apply-iam-role.assume-role.json" user="harold" file=File.read(filepath) data=JSON.parse(file) # 基于最后一个ARN构造新条目,不修改原元素 last_arn = data["Role"]["AssumeRolePolicyDocument"]["Statement"][0]["Principal"]["AWS"][-1] new_arn = last_arn.sub(/user\/.*$/, "user/#{user}") # 直接新增条目 data["Role"]["AssumeRolePolicyDocument"]["Statement"][0]["Principal"]["AWS"] << new_arn File.write(filepath, JSON.dump(data))
这样就只会新增一条全新的条目,不会改动原有的最后一个元素。
内容的提问来源于stack exchange,提问作者Jason Michael
相关产品推荐
相关产品推荐

