TL;博士
我很高兴回答您实际提出的问题,但需要指出的是,您所做的本质上是一种反模式,而不是惯用的 Ruby。
我将首先向您展示一种更好的方法来做您正在做的事情,使用转换阶段而不是单一的惯用方法链。接下来,我将介绍一些可以帮助您处理已构建的字符串数据的替代方法。
最后,我还提供了一些您通常应该注意的警告,但对于回答您的问题并不是必不可少的。它们仍然很有用,并且在您尝试调试某些东西时肯定会帮助解决这些问题。
正确的方式
首先,如果可以避免的话,不要做你正在做的事情。以这种方式解决问题会导致非常脆弱的解决方案。相反,只需将您的输入对直接转换为 Hash 或 JSON。例如:
require "json"
pp total_user_input
#=> ["name", "string", "desc", "string", "price", "integer"]
aa = total_user_input.each_slice(2).to_h
#=> {"name"=>"string", "desc"=>"string", "price"=>"integer"}
puts JSON.pretty_generate aa
{
"name": "string",
"desc": "string",
"price": "integer"
}
这将分阶段转换您的输入,并将字符串打印到适合写入文件或以其他方式漂亮打印为 JSON 的 STDOUT。
您的原始问题已回答
如果您坚持尝试修改给定的字符串,我们将从将其表示为 here-document 开始。
your_pseudo_json = <<~STRING
"name": "string",
"desc": "string",
"price": "integer",
STRING
对于这个给定的字符串,您的选择有限。使用 Windows 样式的换行符而不是 Unix 样式的换行符也会使您的生活复杂化,但您可以通过以下两种方式之一来处理:
使用系统的$/ 记录分隔符,可能是默认定义的,或者自己设置。然后你可以使用 String#chomp。例如:
# If you have to set it explicitly, do so by assigning to $/
# NB: You may not. I don't have a Windows system to check.
$/ = "\r\n"
your_pseudo_json.chomp!(",#{$/}")
使用锚定正则表达式仅删除末尾的项目。无论您的平台的行尾如何,这都将起作用。例如:
your_pseudo_json.sub! /,(?:\r?\n)\z/, ""
如果您正在运行支持String#delete_suffix 的较新 Ruby!那么你几乎可以像#chomp 一样执行此操作,但使用没有插值的简单字符串。例如:
# for Windows line endings
your_pseudo_json.delete_suffix! ",\r\n"
# for *nix-style line endings
your_pseudo_json.delete_suffix! ",\n"
注意事项
在 Irb 或 Pry 中使用非 Bang 方法进行测试
作为测试说明,在您的 REPL 中使用 #chomp、#sub 和 #delete_suffix 的非爆炸方法进行测试,这样您就不必在实验时不断地重新创建字符串。bang 方法将就地修改您的字符串,除非您在默认启用冻结字符串的情况下运行。
冰冻的弦乐
另外,请注意,如果您在程序中使用了 freeze strings pragma,例如:
# frozen_string_literal: true
在 .rb 文件的顶部
RUBYOPT="--enable-frozen-string-literal"
调用 REPL 时在您的环境中
然后使用非爆炸方法并将结果分配回不同(甚至相同)的变量。复制冻结字符串的未冻结副本超出了您当前问题的范围,因此我什至根本不会提及它,除非防止其他读者对该主题的一般自行车脱落。:)