Ruby的%
格式化运算符允许使用散列替换模板值:
"%{a}" % { a: "banana" } # => "banana"
但是,这不适用于动态哈希:
"%{a}" % Hash.new { |hash, key| hash[key] = "banana" } # => KeyError
有解决方法吗?
编辑:此Y的X正在从每个键的可能值数组创建格式哈希。我目前的解决方案是这样的:
content = Hash[CONTENT.map { |k, v| [k, v.sample] }]
但是,我认为这非常难看,并且作为动态解决方案会更好。
答案 0 :(得分:0)
我认为你不能做你想做的事,至少不能做MRI。
如果您浏览代码,您会发现String#%
最终在sprintf.c
中的C中实现了%{x}
。 C实现的if (sym != Qnil) nextvalue = rb_hash_lookup2(hash, sym, Qundef);
if (nextvalue == Qundef) {
rb_enc_raise(enc, rb_eKeyError, "key%.*s not found", len, start);
}
处理部分does this:
rb_hash_lookup2
sym
调用用于从hash
获取KeyError
密钥的值,如果找不到rb_hash_lookup2
,则会引发rb_hash_lookup2
任何事情(即Qundef
返回VALUE
rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
{
st_data_t val;
if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
return def; /* without Hash#default */
}
return (VALUE)val;
}
)。现在,如果我们查看rb_hash_lookup2
,我们会发现它明确地不使用哈希的默认值:
def
请注意,如果找不到密钥,它会使用return def; /* without Hash#default */
参数而不是哈希的默认值:
rb_hash_lookup2
如果您查看Hash#[]
implementation,您会发现它与return def;
之间的唯一区别在于return hash_default_value(hash, key);
被替换为:
String#%
你的问题是:Hash#[]
明确地绕过了哈希的默认值逻辑。由于所有这一切都发生在直接C调用中,因此您无法获取猴子补丁Hash#fetch
,Hash#has_key?
,String#%
或其他任何内容;同样地,你甚至不能将Hash子类化并覆盖任何方法以克服String#%
的脑损伤。
我认为你的丑陋解决方案不如替代方案那么难看(重新实现A Column ------ B Column ------ C Column
John ------ 09/08/2015 ---- Publish
Marie ------ 17/08/2015 ---- Publish
John ------ 08/08/2015 ---- Hold
,破解乱七八糟的正则表达式......)。
YMMV当然还有其他Ruby实现。
答案 1 :(得分:0)
您可以使用Hash#values_at显式初始化字符串的键,但这是一种黑客行为:
"%{a}, %{b}" % Hash.new {|h, k| h[k] = "banana" }.tap {|h| h.values_at(:a, :b) }