python: как прервать соответствие регулярного выражения

Я перебираю строки в большом количестве загруженных текстовых файлов и выполняю сопоставление с регулярным выражением в каждой строке. Обычно матч занимает меньше секунды. Однако иногда матч занимает несколько минут, иногда матч вообще не заканчивается и код просто зависает (пару раз подождал час, потом сдался). Поэтому мне нужно ввести какой-то тайм-аут и сообщить коду соответствия регулярного выражения, чтобы он остановился через 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, называемого , ни , мы когда-нибудь доберемся здесь? в выводе, код просто застрял в 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, называемую , в выводе - и я все еще могу остановить свой скрипт, используя CTRL-C . Если я теперь изменю timeout_handler следующим образом:

class TimeoutException(Exception): 
    pass 

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

и заключу фактический вызов re.match (...) в try ... за исключением TimeoutException , соответствие регулярному выражению действительно прерывается. К сожалению, это работает только в моем простом однопоточном сценарии песочницы, который я использую, чтобы попробовать разные вещи. В этом решении есть несколько ошибок:

  • сигнал срабатывает только один раз, если существует более одной проблемной линии, I ' m застрял на втором
  • , таймер начинает отсчет прямо здесь, а не тогда, когда начинается фактический синтаксический анализ
  • из-за GIL, я должен выполнить всю настройку сигналов в основном потоке, а сигналы принимаются только в основном нить; это противоречит тому факту, что несколько файлов предназначены для одновременного анализа в отдельных потоках - также возникает только одно глобальное исключение тайм-аута, и я не понимаю, как узнать, в каком потоке мне нужно на него реагировать
  • I ' я уже несколько раз читал, что потоки и сигналы не очень хорошо сочетаются

. Я также рассматривал возможность сопоставления регулярных выражений в отдельном процессе, но прежде чем я перейду к этому, я подумал, что лучше проверить здесь, не сталкивался ли кто-нибудь эта проблема раньше и могла бы дать мне несколько советов, как ее решить.

Обновите

регулярное выражение выглядит так (ну, в любом случае, одно из них, проблема возникает и с другими регулярными выражениями; это самый простой):

'^ (\ 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, -

Как сказано, regex обычно работает нормально - я могу проанализировать несколько сотен файлов с несколькими сотнями строк менее чем за минуту. Однако именно тогда файлы будут завершены - код, кажется, зависает с файлами с неполными строками, такими как, например,

`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 движок) - и это тоже убегает.

7
задан ssc 14 March 2011 в 13:56
поделиться