10

如何将函数参数列表规范化为字符串,以便两个参数列表转换为相同的字符串,如果它们实际上是等效的?该算法应

  1. 深入比较嵌入式哈希和列表,而不是通过引用
  2. 忽略哈希键顺序
  3. 忽略 3 和“3”之间的区别
  4. 生成一个相对易读的字符串(不是必需的,但很好用于调试)
  5. 表现良好(XS 优于 Perl)

这对于memoization是必要的,即根据函数的参数缓存函数的结果。

作为一个稻草人的例子,Memoize使用它作为默认的规范化器,它失败了 #1 和 #3:

$argstr = join chr(28),@_;  

有一段时间我的首选标准化器是

JSON::XS->new->utf8->canonical

但是,根据标量最近的使用方式,它对数字 3 和字符串“3”的处理方式不同。这可以为本质上等效的参数列表生成不同的字符串,并降低记忆的好处。(绝大多数函数不会知道或关心它们是否得到 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。

谢谢!

4

2 回答 2

2

几乎任何序列化程序都会以不同的方式处理 3 和“3”,因为它不知道数字和字符串化数字对您来说是相同的,并且这种假设对于一般数据是错误的。您必须自己规范化输入或输出。

对于输入,深度扫描将任何字符串化数字替换为其值+0 即可。如果您知道确切的数字可能在哪里输入,则可以大大缩短此扫描时间。

对于输出,一些简单的状态机甚至正则表达式(是的,我知道输出不规则)很可能足以将纯数字字符串值剥离为数字。

于 2012-05-31T14:12:28.150 回答
2

YAML默认情况下,它的后代排序哈希键。设置$YAML::SortKeys = 2为对深度哈希进行排序。

设置$YAML::Stringify为真值和设置$YAML::XS::QuoteNumericStrings为假值将帮助您标准化数值。后一种设置将“取消引用”一个看起来像数字的字符串值。


此外,您可以使用$Data::Dumper::Sortkeys = 1规范化输出顺序Data::Dumper。设置$Data::Dumper::Useqq = 1将取消引用看起来像数字的字符串。

于 2012-05-31T15:23:34.363 回答