2012-05-31 26 views
9

如何規範化函數參數列表到一個字符串,以便兩個參數列表轉換爲相同的字符串iff它們實際上是等效的?該算法應該如何正常化記憶的Perl函數參數?

  1. 比較嵌入散列和列表深,而不是通過引用
  2. 忽略散列鍵順序
  3. 忽略3和「3」
  4. 產生相對可讀的字符串之間差(不是必需的,但好到有調試)

這是必要的表現良好(XS優於的Perl),即基於其參數緩存函數的結果。

作爲一個稻草人例如,Memoize使用此作爲默認正規化,從而未能#1和#3:

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

有一段時間我去到正規化是

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

然而,根據最近使用的標量的方式來處理數字3和字符串「3」differently。這可以爲基本上等價的參數列表生成不同的字符串,並降低記憶收益。 (絕大多數的功能將不知道或不關心,如果他們得到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

還有[Test :: More](http://metacpan.org/module/Test::More)的is_deeply,和[Test :: Deep](http://metacpan.org/module/Test :: Deep)的eq_deeply。 – Ether

回答

2

幾乎任何串行將把3和「3」不同,因爲它不具備知識號和字符串化的數量同樣爲你和這個假設是一般的數據錯誤。您必須自己規範輸入或輸出。

對於輸入,深度掃描與它的值+ 0將做更換任何字符串化數。如果您知道輸入數字的確切位置,則可以大大縮短此掃描時間。

對於輸出,一些簡單的狀態機,甚至正則表達式(是的,我知道,輸出不正規)將最有可能足以僅數字符串值刪除爲數字。

+0

那麼,不,我列出了上面的一些序列化程序(如Data :: Dump和FreezeThaw),但沒有。 :)也許你的意思是「任何優秀的序列化程序*都應該*不同地對待3和」3「。我不太確定,因爲Perl值在字符串和數字之間可能會變得輕鬆隨意。 –

+0

重新掃描,我提到輸入掃描對於性能而言是不理想的。如果必須完成,我希望它在XS中。但是,如果序列化器可以選擇關閉這個區別,那麼效率會更高。 –

+0

那麼我提到的輸出掃描呢?這應該足夠快。比較依賴於未記錄的怪癖的一個重要的優點是,您可以始終確保手動剝離值確實會被剝離。 –

2

YAML,默認情況下它的後代排序哈希鍵。設置$YAML::SortKeys = 2以獲得對深度哈希進行排序。

設置$YAML::Stringify真實值和設定$YAML::XS::QuoteNumericStrings爲假值將幫助您恢復正常數值。後者設置將「取消」一個看起來像數字的字符串值。


此外,您還可以使用$Data::Dumper::Sortkeys = 1Data::Dumper正常化的輸出順序。設置$Data::Dumper::Useqq = 1將取消看起來像數字的字符串。

+0

對不起,但不行,YAML :: XS的行爲與任何串行器應該一樣。試試'perl -MYAML :: XS -e'我的$ v =「0333」;打印YAML :: XS ::轉儲$ v; $ v + 0;打印YAML :: XS ::轉儲$ v;打印「$ v \ n」;'' –

+0

@Oleg V. Volkov - 感謝您的評論我瞭解了更多關於'$ YAML :: XS :: QuoteNumericStrings'是什麼和編輯我的答案。但我會認爲0333「和333」和0333(即219)應被視爲OP的不同輸入。 – mob

+0

只需「333」將完全相同。 –