如何规范化字符串的函数参数列表,以便两个参数列表转换为相同的字符串iff它们实际上是等效的?算法
这对于memoization是必要的,即根据其参数缓存函数的结果。
作为一个稻草人的例子,Memoize使用它作为默认规范化器,它失败了#1和#3:
$argstr = join chr(28),@_;
有一段时间我的首选标准化器是
JSON::XS->new->utf8->canonical
然而,它根据最近使用标量的方式处理数字3和字符串“3”differently。这可以为基本等效的参数列表生成不同的字符串,并降低memoization的好处。 (绝大多数职能部门不知道或不关心他们是3还是“3”。)
为了好玩,我查看了一堆序列化程序,看看哪些区分3和“3”:
Data::Dump : equal - [3] vs [3]
Data::Dumper : not equal - [3] vs ['3']
FreezeThaw : equal - FrT;@1|@1|$1|3 vs FrT;@1|@1|$1|3
JSON::PP : not equal - [3] vs ["3"]
JSON::XS : not equal - [3] vs ["3"]
Storable : not equal - <unprintable>
YAML : equal - ---\n- 3\n vs ---\n- 3\n
YAML::Syck : equal - --- \n- 3\n vs --- \n- 3\n
YAML::XS : not equal - ---\n- 3\n vs ---\n- '3'\n
在报告“相等”的那些中,不知道如何让它们忽略散列键顺序。
我可以事先查看参数列表并对所有数字进行字符串化,但这需要进行深层复制并违反#5。
谢谢!
答案 0 :(得分:2)
几乎任何序列化程序都会以不同的方式处理3和“3”,因为它不知道数字和字符串化数字对您来说是相同的,并且这种假设对于一般数据是错误的。您必须自己标准化输入或输出。
对于输入,深度扫描将替换任何带字符串的数字,其值为+ 0。如果你知道输入的确切数字在哪里,你可以大大缩短这个扫描。
对于输出,一些简单的状态机甚至regexp(是的,我知道输出不是常规的)很可能足以将只有数字的字符串值去掉数字。
答案 1 :(得分:2)
YAML
及其后代排序哈希键。设置$YAML::SortKeys = 2
以对深度哈希进行排序。
将$YAML::Stringify
设置为真值并将$YAML::XS::QuoteNumericStrings
设置为false值可帮助您规范化数值。后一种设置将“取消引用”一个看起来像数字的字符串值。
此外,您可以使用$Data::Dumper::Sortkeys = 1
使用Data::Dumper
规范化输出顺序。设置$Data::Dumper::Useqq = 1
将取消引用看起来像数字的字符串。