python:如何中断正则表达式匹配
我在大量下载的文本文件中迭代这些行,并在每行上进行正则表达式匹配。通常,比赛不到一秒钟。然而,有时一场比赛需要几分钟,有时比赛根本没有结束,代码只是挂起(等了几次一个小时,然后就放弃了)。因此,我需要引入某种超时,并以某种方式告诉正则表达式匹配代码在10秒左右后停止。我可以接受这样一个事实:我将丢失正则表达式应该返回的数据 我尝试了以下方法(当然,在一个代码示例中已经显示了两种不同的基于线程的解决方案): 但是我既没有得到名为的python:如何中断正则表达式匹配,python,regex,multithreading,timeout,signals,Python,Regex,Multithreading,Timeout,Signals,我在大量下载的文本文件中迭代这些行,并在每行上进行正则表达式匹配。通常,比赛不到一秒钟。然而,有时一场比赛需要几分钟,有时比赛根本没有结束,代码只是挂起(等了几次一个小时,然后就放弃了)。因此,我需要引入某种超时,并以某种方式告诉正则表达式匹配代码在10秒左右后停止。我可以接受这样一个事实:我将丢失正则表达式应该返回的数据 我尝试了以下方法(当然,在一个代码示例中已经显示了两种不同的基于线程的解决方案): 但是我既没有得到名为的timeout\u处理程序,也没有得到输出中的行,代码只是停留在解析
timeout\u处理程序,也没有得到输出中的行,代码只是停留在解析数据文件中
更糟糕的是,我甚至不能用CTRL-C
停止程序,而是需要查找python进程号并终止该进程。一些研究表明,Python的人知道正则表达式C代码正在流失:
我确实在使用信号方面取得了一些成功:
signal(SIGALRM, timeout_handler)
alarm(8)
data_sets = parse_data_files(config(), data_provider)
alarm(0)
这将获得输出中名为
行的timeout\u处理程序,我仍然可以使用CTRL-C
停止脚本。如果我现在修改超时\u处理程序,如下所示:
class TimeoutException(Exception):
pass
def timeout_handler(signum, frame):
raise TimeoutException()
并将对re.match(…)
的实际调用包含在try
中<除了TimeoutException
子句之外,正则表达式匹配实际上会被中断。不幸的是,这只适用于我用来尝试东西的简单的单线程沙盒脚本。此解决方案存在一些问题:
- 信号只会触发一次,如果有多条线路有问题,我会被卡在第二条线路上
- 计时器就在那里开始计数,而不是在实际解析开始时
- 由于GIL,我必须在主线程中进行所有信号设置,并且信号仅在主线程中接收;这与多个文件要在单独的线程中同时解析的事实相冲突——也只引发了一个全局超时异常,我不知道如何知道需要在哪个线程中对其作出反应
- 我已经读过好几次了,线程和信号不能很好地混合
我也考虑过在一个单独的过程中进行正则表达式匹配,但是在我开始之前,我想我最好在这里检查一下是否有人曾经遇到过这个问题,并可以给我一些关于如何解决这个问题的提示
更新
正则表达式如下所示(不管怎样,其中一个正则表达式也会出现问题;这是最简单的正则表达式):
“^(\d{5}),.+?,(\d{8}),(\d{4}),.+?,.+?,“+37*”(.*?,“+”(.*?)$”
样本数据:
95756,“KURN”,201103112130,-34.00151.21260,06.0,-9999.0,-9999.0,-9999.0,-9999.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,-9999,-9999,-9999,-9999,-9999,-9999,-9999,-9999,-9999,-9999
如前所述,正则表达式通常执行正常-我可以在不到一分钟内用几百行解析几百个文件。这时文件就完成了——代码似乎挂起了行不完整的文件,例如
`95142,“YMGD”,201103111700,-12.06134.23310,05.0,25.8,23.71004.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
我也遇到过这样的情况,正则表达式似乎立即返回并报告不匹配
更新2
我只是很快地通读了一遍,但据我所知,这不是原因——我没有嵌套任何重复运算符
我在Mac OSX上,所以我不能使用RegexBuddy分析我的regex。我尝试过(显然它在内部使用Perl正则表达式引擎),但也没有成功。你不能用线程来完成。继续你的想法,在一个单独的过程中进行匹配。Python中的线程是一个怪兽。全局解释器锁本质上是解释器周围的一个大锁,这意味着每次只有一个线程在解释器内执行
线程调度委托给操作系统。Python本质上是向操作系统发出信号,表示另一个线程可能在执行了一定数量的“指令”后获得锁。因此,如果Python由于一个失控的正则表达式而忙,它就永远不会有机会向操作系统发出信号,表示它可能试图为另一个线程获取锁。因此,使用信号的原因;他们是打断别人的唯一方式
我是Nosklo的,继续使用单独的流程。或者,尝试重写正则表达式,使其不会跑掉。看见这可能是也可能不是regex性能不佳的原因,并且不可能更改您的regex。但是,如果这是原因,而且可以改变,那么你可以避免多个过程来减轻你自己的头痛。而不是试图用超时解决ReGEXP挂断问题,也许值得考虑一种完全不同的方法。如果数据实际上只是逗号分隔的值,那么使用-module或仅仅使用
line.split(“,”
)应该可以获得更好的性能,因为您将遇到灾难性的回溯;不是因为嵌套的量词,而是因为你的量化字符也可以匹配分隔符,而且因为有很多分隔符,在某些情况下你会得到指数时间
除了看起来更像CSV解析器的作业之外,请尝试以下操作:
r'^(\d{5}), [^,]+, (\d{8}), (\d{4}), [^,]+, [^,]+,' + 37 * r' ([^,]+),' + r' ([^,]+)$'
通过明确禁止逗号在分隔符之间匹配,您将极大地提高正则表达式的速度
例如,如果逗号可能出现在带引号的字符串中,则只需交换[^,]+
(在
r'^(\d{5}), [^,]+, (\d{8}), (\d{4}), [^,]+, [^,]+,' + 37 * r' ([^,]+),' + r' ([^,]+)$'
(?:"[^"]*"|[^,]+)