如何用正则表达式杀死Java
我們最近偶然發現了一個我們絕對不了解的現象:您可以使用簡單的正則表達式殺死任何Java IDE以及任何Java進程…
回到大學后,我被告知正則表達式(稱為正則語法或3型語法)總是以有限狀態的自動機結束,因此可以在線性時間內進行處理(輸入長度??加倍,處理時間加倍)。 但是,這僅適用于“理智”的表達式。 正則表達式也可能導致不確定的有限狀態自動機,事情可能會變得很糟。
考慮一下表達式:(0 *)* A這將是任意數量的零,后跟一個大寫的A?,F在,如果對該表達式使用Matcher.find() ,那么只要輸入中存在匹配項,一切都很好。 但是,如果您以“ 00000000000000000000”作為輸入調用此程序,則程序將掛起(Eclipse或IntelliJ中的regex控制臺以及每個(基于Java的)在線正則表達式服務也將掛起)。
乍一看似乎是一個無限循環,但變成了災難性的回溯 。 這基本上意味著匹配器檢測到在輸入末尾沒有找到A。 現在,外部量詞繼續向后退–內在量詞又一次向前–沒有結果。 因此,匹配器將逐步重試所有組合以找到匹配項。 它最終將返回(沒有匹配項),但是它的復雜性(以及因此的運行時)是冪的(將一個字符添加到輸入中會使運行時加倍)。 可以在這里找到詳細的描述: 災難性的回溯
這是我測量的一些運行時(對于每個添加的字符,運行時幾乎幾乎翻了一番):
0000000000: 0.1ms 00000000000: 0.2ms 000000000000: 0.7ms 0000000000000: 1.3ms 00000000000000: 1.7ms 000000000000000: 3.5ms 0000000000000000: 7.2ms 00000000000000000: 13.9ms 000000000000000000: 27.5ms 0000000000000000000: 55.5ms 00000000000000000000: 113.0ms 000000000000000000000: 226.4ms 0000000000000000000000: 439.1ms 00000000000000000000000: 886.0ms簡要說明一下:對于像這樣的微型基準測試,由于HotSpot JIT將在某個時候跳入并優化代碼,因此您始終需要“預熱” JVM。 因此,第一次運行如下所示:
0000000000: 6.8ms 00000000000: 11.8ms 000000000000: 25.5ms 0000000000000: 39.5ms 00000000000000: 6.3ms <- JIT jumped in and started to translate 000000000000000: 5.4ms to native code. 0000000000000000: 7.1ms 00000000000000000: 14.2ms 000000000000000000: 26.8ms 0000000000000000000: 54.4ms 00000000000000000000: 109.6ms 000000000000000000000: 222.1ms 0000000000000000000000: 439.2ms 00000000000000000000000: 885.6ms那么,這里的要點是什么? 如果您正在運行服務器應用程序或許多用戶使用的關鍵操作,除非您真的信任他們,否則不要讓他們輸入正則表達式。 那里有正則表達式實現,可以檢測到此問題并中止,但是Java(JDK 8以下)沒有。
注意: 您可以使用本地IDE或小型Java程序來測試此內容,但是請不要開始淘汰那里的所有regex測試器網站。 那些家伙免費提供了一個不錯的工具,所以這是相當不公平的。
這是我使用的微小基準:
public class Test {public static void main(String[] args) {for (int runs = 0; runs < 2; runs++) {Pattern pattern = Pattern.compile("(0*)*A");// Run from 5 to 25 charactersfor (int length = 5; length < 25; length++) {// Build input of specified lengthString input = "";for (int i = 0; i < length; i++) { input += "0"; }// Measure the average duration of two calls... long start = System.nanoTime();for (int i = 0; i < 2; i++) {pattern.matcher(input).find();}System.out.println(input + ": " + ((System.nanoTime() - start) / 2000000d) + "ms");}}} } 參考: Andy的軟件工程專欄博客中的JCG合作伙伴 Andreas Haufler 提供了如何使用正則表達式殺死Java 。翻譯自: https://www.javacodegeeks.com/2013/09/how-to-kill-java-with-a-regular-expression.html
總結
以上是生活随笔為你收集整理的如何用正则表达式杀死Java的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深圳车牌还可以备案吗现在(深圳车牌还可以
- 下一篇: Java正则表达式中的反向引用