使用带字符串和%的动态查找哈希

时间:2015-08-10 00:42:44

标签: ruby string hash

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] }]

但是,我认为这非常难看,并且作为动态解决方案会更好。

2 个答案:

答案 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#fetchHash#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) }