歡迎光臨
每天分享高質量文章

一個正則式引發的血案

(點選上方公眾號,可快速關註)


來源:ImportNew – keywords

關於作者:Vlad Mihalcea是一個專註於軟體整合,高可擴充套件性和併發程式設計挑戰的軟體架構師

我從來沒有想到我可以看到一個差勁的正則式造成一臺伺服器沒有響應。但它偏偏就在我們的一個伺服器上面發生了,結果導致了它毫無響應。

假設我們在解析一些外部汽車經銷商的資訊。我們想在各種各樣的輸入中找到那些帶”no air conditioning”的汽車,同時不要匹配那些諸如”mono air conditioning”的樣式。

那個搞掛我們伺服器的正則式類似於這樣:

String TEST_VALUE = “ABS, traction control, front and side airbags, 

Isofix child seat anchor points, no air conditioning, electric windows,

 \r\nelectrically operated door mirrors”;

 

double start = System.nanoTime();

Pattern pattern = Pattern.compile(“^(?:.*?(?:\\s|,)+)*no\\s+air\\s+conditioning.*$”);

assertTrue(pattern.matcher(TEST_VALUE).matches());

double end = System.nanoTime();

LOGGER.info(“Took {} micros”, (end – start) / (1000 ));

兩分鐘後,這個測試還沒有停止並且一個CPU核已經滿負載運行了。

首先,我們是在整個輸入資料上使用matches方法的,所以不需要開始(^)和結束($)匹配符。其次,由於輸入字串中存在換行符,我們必須讓正則式執行在多行樣式下:

Pattern pattern = Pattern.compile(“(?:.*?(?:\\s|,)+)*no\\s+air\\s+conditioning.*?”, Pattern.MULTILINE);

讓我們看一看不同版本的正則式的行為:

為什麼不用String.indexOf()

儘管它應該比正則式快很多,但我們仍需要考慮字串開始的情況,例如一些像”mono air conditioning”的樣式;以及用製表符或多個空格符分開的輸入。像這樣自定製的實現可能會快一些,但都缺少靈活性而且需要更多的時間去實現。

結論

正則式是樣式匹配的利器,但你不應該隨心所欲的使用它。因為很小的改變可能帶來很大的不同。第一個正則式事與願違的原因是由於catastrophic backtracking。這是一個每位開發者在寫正則式之前都應當註意的一個現象。

看完本文有收穫?請轉發分享給更多人

關註「ImportNew」,提升Java技能

贊(0)

分享創造快樂