一種簡單的字元轉義演算法
有的時候我們希望將字元串中的某些特殊字元替換成其他字元,來方便我們對於分隔符的使用,比如說我們需要轉義字元串中的小數點字元(.),來將字元串拼成用點號隔開的欄位,來形成KVDB中的一個key;或者我們需要轉義字元串中的/、?、*來形成一個文件名(當然,真正的文件名需要轉義的字元可能會更多)。除了採用urlencode、base64以及各種各樣的現成的escape方法以外,有一種簡單的方法可以快速寫出這樣的代碼,很適合轉義少量字元,而基本不破壞整個字元串的可讀性,代碼也只有一行。
假設我們要轉移一些字元,我們可以採用這樣的方法:
- 挑選一個不在要轉移字元當中的新字元。一般來說我比較喜歡的字元包括+和$,可以按情況選擇。盡量選擇出現概率低的符號,盡量不要選擇數字和字母(你不會喜歡一個單詞或者數字中間跑出來符號這種事情)
- 將依次替換成提前選定的e開頭的字元串。這些字元串應該符合如下的規則:
- 除了最後一個對應的字元串以外,其他字元串不能包含e。
- 不能為另一個字元串的前綴
- 不能包含
在解轉義的時候,只需要:
按的順序,將相應的字元串重新替換回原來的字元即可。
比如說我們現在想要轉義小數點(.),冒號(:),斜杠(/)三個字元,我們選中$作為字元e,然後分別將四個字元替換成$_, $+, $-和$$:
def escape_key(k):n return k.replace($, $_).replace(., $+)n .replace(:, $-).replace(/, $$)nndef unescape_key(k):n return k.replace($$, /).replace($-, :)n .replace($+, .).replace($_, $)n
證明正確性:
首先,這個編碼方式形成了一種前綴碼:不以e開頭的字元都表示自己;e開頭的相應的字元串表示相應的字元。用這種方法編碼後的字元串是無歧義的。由於e開頭相應字元串中沒有包含要轉移的字元,因此我們所有替換的字元都是原字元串中的字元,得到的結果與前綴編碼方法得到的結果相同。更進一步,將全部替換成相應字元串,後面字元暫不轉移的編碼方式也構成了前綴碼,因此我們每一步替換都得到一個前綴碼編碼的字元串,它都是無歧義的。
接下來考慮解碼的過程,對於每一個,在編碼時對它進行替換之前,由於所有字元e開頭的字元串都是一個e開頭的轉義字元串,這些字元串不是對應字元串的前綴,對應字元串也不是他們的前綴,因此原串中不存在對應字元串,替換後,從前往後匹配到的所有字元串都代表。因此解碼的時候,將這個字元串重新替換回,就可以回到被替換掉之前的狀態。
當所有的都被替換回去之後,字元串中所有出現的字元e都一定是以e的轉義字元串的形式出現的,一一對應,因此將這個字元串替換回e就可以回到原來的字元串了。
例如前面的例子中:>>> escape_key(a/b.c:def/ghi::jkl////.:/..mn)na$$b$+c$-def$$ghi$-$-jkl$$$$$$$$$+$-$$$+$+mnn>>> unescape_key(_)na/b.c:def/ghi::jkl////.:/..mnn
推薦閱讀:
※全球第一款開源線下搜索引擎OpenGenus,線下搜索代碼、演算法
※自己做個AlphaGo(一)(井字棋)
※演算法正在形成新型生態系統,它將生生不息,次元書摘@《終極演算法》