如何以惯用方式将HTTP查询字符串转换为Raku Hash?
优雅的惯用实现方式
方法1:拆分后解构赋值生成Pair
这是最直观且符合Raku惯用风格的写法,用split拆分键值对和键值,结合解构赋值生成Pair:
my $s = 'one=iwejdoewde&two=ijijjiiij&three=&four=endinghere'; my %h = $s.split('&').map: -> $kv { my ($key, $val) = $kv.split('=', 2); # 第二个参数2确保值里的=不会被误拆分 $key => $val }; say %h; # 输出:{four => endinghere, one => iwejdoewde, three => , two => ijijjiiij}
方法2:更简洁的链式调用
利用Raku的方法链式调用特性,进一步简化代码:
my %h = $s.split('&').map: { .split('=', 2).pair }; say %h;
这里split('=', 2)返回包含键和值的两元素列表,调用pair方法直接将其转换为键 => 值的Pair,Hash会自动将每个Pair解析为键值对。
方法3:正则匹配正确生成Pair
如果想用正则实现,需要从Match对象中提取捕获组生成Pair,而非错误使用pairup:
my %h = $s.split('&').map: { my ($key, $val) = .match(/(.+)=(.*)/).list; $key => $val }; say %h;
为什么之前的match+pairup会出错
你之前的代码中,*.match(/ (.+) \= (.*) /).pairup的问题在于:match返回的Match对象调用pairup时,会生成捕获组索引与对应捕获值的Pair列表(比如匹配one=two时,返回(0 => 「one」, 1 => 「two」)),并非你预期的单个one => two Pair。当这些Pair列表被map返回后,赋值给Hash时,Hash会将连续的两个Pair当作一组键值对(第一个Pair作为键,第二个作为值),最终得到错误的结构。
对比原代码的优势
原代码用comb(/<-[&]>+/)拆分键值对,虽然能工作,但split('&')更直观且性能更优;同时用解构赋值或pair方法生成Pair,比手动取数组元素@a[0] => @a[1]更简洁易读,也符合Raku的惯用写法。
内容的提问来源于stack exchange,提问作者Richard Hainsworth
相关产品推荐
相关产品推荐

