簡體   English   中英

python:如何中斷正則表達式匹配

[英]python: how to interrupt a regex match

我迭代了大量下載的文本文件中的行,並在每一行上進行正則表達式匹配。 通常,匹配不到一秒鍾。 但是,有時匹配需要幾分鍾,有時匹配根本沒有完成,代碼只是掛起(等了一個小時幾次,然后就放棄了)。 因此,我需要引入某種超時並以某種方式告訴正則表達式匹配代碼在10秒左右后停止。 我可以忍受這樣一個事實,即我將丟失正則表達式應該返回的數據。

我嘗試了以下(當然,在一個代碼示例中顯示了2個不同的,基於線程的解決方案):

def timeout_handler():
    print 'timeout_handler called'

if __name__ == '__main__':
    timer_thread = Timer(8.0, timeout_handler)
    parse_thread = Thread(target=parse_data_files, args=(my_args))
    timer_thread.start()
    parse_thread.start()
    parse_thread.join(12.0)
    print 'do we ever get here ?'

但我既沒有得到timeout_handler calledtimeout_handler calleddo we ever get here ? 在輸出中的行,代碼只是卡在parse_data_files

更糟糕的是,我甚至無法使用CTRL-C停止程序,而是需要查找python進程號並終止該進程。 一些研究表明Python人員知道正在運行的正則表達式C代碼: http//bugs.python.org/issue846388

我確實使用信號取得了一些成功:

signal(SIGALRM, timeout_handler)
alarm(8)
data_sets = parse_data_files(config(), data_provider)
alarm(0)

這讓我得到輸出中timeout_handler called line的timeout_handler called - 我仍然可以使用CTRL-C來停止我的腳本。 如果我現在修改timeout_handler,如下所示:

class TimeoutException(Exception): 
    pass 

def timeout_handler(signum, frame):
    raise TimeoutException()

並且在try ...中包含對re.match(...)的實際調用... except TimeoutException子句except TimeoutException ,正則表達式匹配實際上會被中斷。 不幸的是,這只適用於我用來試用東西的簡單的單線程沙箱腳本。 這個解決方案有一些問題:

  • 信號只觸發一次,如果有多條有問題的線,我就會卡在第二條線上
  • 計時器在那里開始計數,而不是在實際解析開始時
  • 由於GIL,我必須在主線程中進行所有信號設置,並且信號僅在主線程中接收; 這與多個文件同時在不同的線程中被解析的事實發生沖突 - 也只引發了一個全局超時異常,我不知道如何知道我需要對哪個線程作出反應
  • 我已經多次讀過線程和信號不能很好地混合

我也考慮過在一個單獨的過程中進行正則表達式匹配,但在我進入之前,我想我最好先檢查一下是否有人之前遇到過這個問題並且可以給我一些關於如何解決它的提示。

更新

正則表達式看起來像這樣(好吧,其中一個,無論如何,問題也出現在其他正則表達式中;這是最簡單的一個):

'^(\\d{5}), .+?, (\\d{8}), (\\d{4}), .+?, .+?,' + 37 * ' (.*?),' + ' (.*?)$'

樣本數據:

95756, "KURN ", 20110311, 2130, -34.00, 151.21, 260, 06.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999.0, -9999, -9999, 07.0, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -

如上所述,正則表達式通常表現良好 - 我可以在不到一分鍾的時間內解析數百個帶有數百行的文件。 但是,當文件完成時 - 代碼似乎掛起了包含不完整行的文件,例如

`95142, "YMGD ", 20110311, 1700, -12.06, 134.23, 310, 05.0, 25.8, 23.7, 1004.7, 20.6, 0.0, -9999, -9999, 07.0, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999, -9999

我也得到了正則表達式似乎立即返回並報告不匹配的情況。

更新2

我只是快速閱讀了災難性的文章 ,但據我所知,到目前為止,這不是原因 - 我沒有嵌套任何重復操作符。

我在Mac OSX上,所以我不能使用RegexBuddy來分析我的正則表達式。 我嘗試過RegExhibit (它顯然在內部使用了Perl RegEx引擎) - 而且它也跑掉了。

你正在遇到災難性的回溯; 不是因為嵌套量詞,而是因為你的量化字符也可以匹配分隔符,並且因為它們中有很多,所以在某些情況下你會得到指數時間。

除了它看起來更像是CSV解析器的工作之外,請嘗試以下操作:

r'^(\d{5}), [^,]+, (\d{8}), (\d{4}), [^,]+, [^,]+,' + 37 * r' ([^,]+),' + r' ([^,]+)$'

通過明確禁止逗號匹配分隔符,您將極大地加速正則表達式。

例如,如果逗號可能出現在帶引號的字符串中,那么只需交換[^,]+ (在你期望的地方)

(?:"[^"]*"|[^,]+)

為了顯示:

在第一個示例中使用正則表達式,RegexBuddy在正則表達式引擎的793步之后報告成功匹配。 對於第二個(不完整的行)示例,它在正則表達式引擎的1.000.000步之后報告匹配失敗(這是RegexBuddy放棄的地方; Python將繼續攪拌)。

使用我的正則表達式,成功匹配發生在173步驟中,失敗發生在174。

可能值得考慮一種完全不同的方法,而不是試圖用超時來解決正則表達式掛斷問題。 如果您的數據實際上只是逗號分隔值,那么使用csv -module或只使用line.split(",")可以獲得更好的性能。

你不能用線程來做。 繼續你想要在一個單獨的過程中進行比賽。

Python中的線程是一種奇怪的野獸。 全局解釋器鎖本質上是解釋器周圍的一個大鎖,這意味着一次只有一個線程可以在解釋器中執行。

線程調度委托給OS。 Python基本上向操作系統發出信號,表示另一個線程可能會在一定數量的“指令”之后鎖定。 因此,如果Python由於失控的正則表達式而忙,它永遠不會有機會向操作系統發出信號,表示它可能會試圖鎖定另一個線程。 因此使用信號的原因; 他們是打斷的唯一方式。

我和Nosklo在一起,繼續使用不同的流程。 或者,嘗試重寫正則表達式,以便它不會逃避。 查看與回溯相關的問題 這可能是也可能不是正則表現不佳的原因,並且可能無法更改正則表達式。 但如果這是原因而且可以改變,那么通過避免多個過程,你將為自己省去很多麻煩。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM