通過全文相似度來尋找相同或相似的代碼

最近筆者在職的公司在不斷的做App的包瘦身工作, 身邊的同事們也研究出了各種各樣實用的工具來輔助加快包瘦身的進程。在這么一個大環境下, 筆者突然又冒出一個很無聊的工具想法

通過文本匹配來尋找相似的方法函數

筆者給這個小工具取了一個非常傳神且牛逼的名字 - SameCodeFinder

和上一個查找Block的無聊的小工具RiskBlockScanner類似, 這個工具筆者覺得也是一個應用面相對比較小的一個工具, 所以筆者自嘲無聊的小工具哈~

筆者自認為這個是一個無聊的小工具, 但是還是堅持把它開發出來了, 因為筆者堅信:

任何一個無聊小眾的作品, 在合適的時機總是能夠幫助到合適的人的!

筆者開發這個小工具除了因為筆者相信這個工具肯定能夠幫助到部分人群以外, 還有另外一個目的是督促自己不要停止學習的步伐哈~

起源-輔助研發自查

查找相似代碼想法的起源是因為筆者在在職的公司項目處于包瘦身的大環境下。在這個大環境下, 筆者身邊的一名同事發明了基于otoollinkmap分析查找無用方法的工具, 該工具在Github上有個類似的開源腳本項目objc_cover。與此同時, 筆者的另外一名同事發表了一種基于Clang來查找無用方法的博文。

受這兩位同事的影響, 筆者就在想自己能搞什么和他們不一樣點的工具么。因為筆者之前用文本掃描的方式搞了一個簡易的快速Block檢查腳本, 筆者就在想能不能通過類似的手段寫一個類似的程序。筆者想借鑒《基于Clang來查找無用方法》的思路進行擴展, 因為該文章里提出了一種將文本內容Hash后進行內容比較, 判斷方法是否完全重合的思路

筆者基于該思路進行擴展, 設想能不能不止比較“完全相同”的方法, 還能比較相似的方法。順著這個思路發現了Google的全文搜索相似度比較的一種算法simhash[7, 8]。

Simhash

關于simhash的介紹引用博文《simhash算法原理及實現》 里的介紹

simhash是google用來處理海量文本去重的算法。 google出品,你懂的。 simhash最牛逼的一點就是將一個文檔,最后轉換成一個64位的字節,暫且稱之為特征字,然后判斷重復只需要判斷他們的特征字的距離是不是<n(根據經驗這個n一般取值為3),就可以判斷兩個文檔是否相似。

上述引用其實有點不完全正確, simhash貌似并不是Google出品的, 第一作者的郵箱后綴明明是普林斯頓大學好不好~ 不過Google將其應用到了網絡爬蟲并發表了一篇文章哈~

PS: 想了解詳情? 閱讀Paper去... =。=

《simhash算法原理及實現》 針對simhash梳理了簡易的原理介紹以及使用判斷距離的漢明距離, 可以便于讀者快速了解, 但是如果大家想要了解更深層次的實現, 可以去閱讀原版paper《Detecting Near-Duplicates For Web Crawling》《Similarity estimation techniques from
rounding algorithms》
。

原理簡析

simhash的生產步驟可以分為如下:

  1. 提取目標文本的關鍵字feature和權重weight, 并成對存儲
    • 如果不知道怎么提取的同學, 可能需要稍微了解全文搜索相關的知識
  2. 將提取出來的關鍵字進行傳統Hash, 輸出二進制的值
  3. 將每一個關鍵字提取的Hash按位進行運算, 如果當前位是1, 則增加對應的權重; 如果當前位是0, 增減少當前對應的權重;
  4. 將最后得出來的hash值, 如果大于等于1, 則當做1處理; 負數和0當做0處理, 得出最終的二進制值

上述步驟可以簡化為下圖, 此圖引用了我的數學之美系列二 —— simhash與重復信息識別中的圖

simhash原理示意

漢明距離

simhash是一種局部敏感Hash。因此可以利用漢明距離去衡量simhash的相似度。

引入Wikipedia的漢明距離介紹:

In information theory, the Hamming distance between two strings of equal length is the number of positions at which the corresponding symbols are different.

字面上意思好像就是兩個字符串在不一樣字符個數的數量, 在我們現在的應用場景就是統計1或者0的個數, 然后他們的個數差就是距離了。。。一般搜索引擎的歷史經驗默認是3

PS: 別問我怎么知道的3的, 我也是從博客里看來的, 沒有數據依據

尋找相似的代碼

尋找完全相似的文件

針對上述理論, 只要是一個文檔都可以計算出兩者的漢明距離, 利用漢明距離來就可以衡量兩個文檔的相似度了。筆者在這里目前沒有做太多的工作, 只不過過濾了文檔的后綴, 讓相當類型的文檔進行相互的比較。

尋找相似的文件和尋找相似的代碼文件, 其實本質上差距不大。代碼文件有一些特性, 例如前面的聲明和引用都有一列類似的地方, 如果在進行simhash計算處理前能夠提前對代碼文件進行預處理的話, 能夠大幅度的提高整個代碼文件相似度計算的精度。

PS: 鑒于思路的完善性和時間成本, 筆者還沒有針對代碼進行預處理

尋找雷同方法函數

既然利用simhash以及漢明距離可以計算兩個文檔的相似度, 然自然可以縮小范圍計算兩個函數方法的相似度。那么問題的關鍵就在于怎么樣才能提取到合適正確的方法函數內容

筆者目前使用的是文本掃描匹配的方式, 但是筆者的同事有提出一種是基于clang插件來提取編譯器預處理之后的內容進行hash比較的可行思路。無奈鑒于實現成本和插件無法獨立運行的方面考慮, 暫時采用的直接掃描匹配文本的方式進行比較。

目前筆者采取的提取方法體方法是:

  1. 用正則匹配獲取方法起始行
  2. 從起始行開始記錄左右括號的格式, 并且將起始行開始的所有字符串記錄
  3. 當左右括號的個數相互抵消的時候默認當做匹配整個方法, 保存整個字符串

鑒于方法匹配需要根據語法實現, 所以目前只能根據每個語言的語法特性進行截獲, 目前SameCodeFinder僅支持Object-C和Java。

語法特性局限了腳本的可擴展性, 步驟一的正則需要和后綴匹配, 步驟二的左右括號在某些語言下不適用, 只能利用發現下一個方法起始行作為步驟三的結束步驟。

Java目前采用正則:

ur"(public|private)(.*)\)\s?{"

Object-C目前采用正則:

ur"(\-|\+)\s?\(.*\).*(\:\s?\(.*\).*)?{?"

排序

無論是尋找雷同的文件還是尋找雷同的方法, 最后計算出的Hash結果都是N * N個的, 那么怎么展示計算的結果呢? 如果把所有的結果都展示出來, 那明顯可閱讀性太低。

目前采用的邏輯是:

  1. N * N 中第一個N只找出距離最小的第一個返回, 這樣過濾結果只保留N個
  2. 將第一步過濾返回的N個結果按照從小到大的方式進行排序

此外,在執行排序的步驟1和步驟2之間, 都可以添加一個最大距離過濾, 默認不超過20, 可以大幅度減少步驟1和步驟2的計算排序過濾時間。

開源實現

筆者基于上述思路以及現成的工具, 利用python腳本花了2天時間去高速實現了一個簡易的python腳本, 并開源到了Github上。

訪問地址: SameCodeFinder

目前開源的版本可能因為筆者使用不當或者開源python版本的simhash的計算太過耗時, 因此在性能上存在一定的性能問題, 計算整個較大的工程需要花費不少的時間(計算一個大型工程是分鐘級別的)。

筆者會在之后尋找突破方法來提高這方面的計算性能~

總結

SameCodeFinder可以幫助大家尋找相似或者完全重疊的方法以及類, 極大程度上可以輔助大家尋找可以復用的代碼。SameCodeFinder的實現思路都是借用Google的全文相似度比較的現成實現, 并沒有什么創新, 但是腳本化和針對語種設計的方法識別, 能夠幫助大家節省不少直接利用simhash去實現的成本。

PS: 個人水平有限, 有錯誤之處請大家及時指出, 隨時交流哈~

參考文獻

  1. CLANG技術分享系列四:IOS APP無用代碼/重復代碼分析
  2. A Python Implementation of Simhash Algorithm
  3. otool
  4. Mac的反編譯工具一:otool (objdump工具的OSX對應工具)
  5. iOS APP可執行文件的組成
  6. simhash算法原理及實現
  7. GS Manku, A Jain, A Das Sarma. Detecting Near-Duplicates For Web Crawling. International Conference on World Wide Web. International Conference on World Wide Web. 141-149. 2007.
  8. M. Charikar. Similarity estimation techniques from
    rounding algorithms. In Proc. 34th Annual Symposium
    on Theory of Computing (STOC 2002), pages
    380–388, 2002.
  9. 我的數學之美系列二 —— simhash與重復信息識別
  10. Locality-sensitive hashing
  11. Hamming_distance
  12. Mach-O Executables
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容