mishuk27 has asked for the wisdom of the Perl Monks concerning the following question:

I have a big text and badly wroten regular expression. :) Matching uses about 100% CPU and can continue several hours. The task is to interrupt matching by timeout in 1 second. I use alarm but it interrupts only in 20-30 minutes. Are there any ways to do in 1 second without modification of regular expression? Thanks in advance.
  • Comment on How to interrupt regular expression matching?

Replies are listed 'Best First'.
Re: How to interrupt regular expression matching?
by johngg (Canon) on May 26, 2008 at 21:55 UTC
    It might be more productive to fix the badly written regex. Why don't you post another SoPW addressing that instead?

    Cheers,

    JohnGG

Re: How to interrupt regular expression matching?
by moritz (Cardinal) on May 26, 2008 at 22:05 UTC
    If the regex comes from possible hostile sources you could try to fork, use BSD::Resource to limit the CPU time for the child, and match it only then. (That's what my evalbot in #perl6 does).

    As said before, if you have control over the regex, fix the regex instead.

      why alarm does not work?
        why alarm does not work?

        It depends on how you are (mis)using it. Show us some code, and maybe we can figure out what you are really asking.

Re: How to interrupt regular expression matching?
by Limbic~Region (Chancellor) on May 26, 2008 at 23:08 UTC
    mishuk27,
    This is a complete guess but perhaps you are using perl 5.8 or above with safe signals enabled (20 - 30 minutes instead of instantly). If so, read up on perl signals and turn off safe-signals to see if that changes anything.

    Cheers - L~R

Re: How to interrupt regular expression matching?
by zentara (Cardinal) on May 27, 2008 at 12:19 UTC
    Update 10 minutes later.... fixed a couple of code bugs

    This is alot more complex than an alarm, but you could run the regex in a separate thread, and have a second parallel thread time it out. Note you need a later version of threads, and Thread::Cancel. Just an idea. This allows you to issue keypress commands too :-)

    #!/usr/bin/perl # untested and various variable and thread resets ignored use warnings; use strict; use Glib; use Term::ReadKey; use threads; use threads::shared; use Thread::Cancel; $|++; ReadMode('cbreak'); # works non-blocking if read stdin is in a thread my $count:shared = 0; my $done:shared = 0; my $thr = threads->new(\&read_in)->detach; my $thr1 = threads->new(\&long_regex); # only can cancel non-detached threads my $main_loop = Glib::MainLoop->new; my $timer = Glib::Timeout->add (100, \&timer_callback, undef, 1 ); $main_loop->run; ReadMode('normal'); # restore normal tty settings sub timer_callback{ #do stuff $count++; print "\n$count\n"; if ( ($count > 10) or ($done == 1)){ $thr1->cancel(); print "thread canceled\n"; return 0; } return 1; } sub long_regex{ while(1){ sleep 1; } $done = 1; } sub read_in{ while(1){ my $char; if (defined ($char = ReadKey(0)) ) { print "\t\t$char->", ord($char),"\n"; #process key presses here #if($char eq 'q'){exit} if(length $char){exit} # panic button on any key :-) } } } __END__

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum