in reply to RE: RE: RE (tilly) 1: SAS log scanner
in thread SAS log scanner
In any case there is overhead to entering a block, and to a hash lookup. Therefore I believe that tye's approach really is faster than your loop. But I went and tested it and found that between the three approaches the difference was all in the compilation. So I went for a longer file (a bit over 4 MB) and found that I was a bit under 27 seconds, tye just over 35, and yours 2 min, 22 seconds. I think tye's is faster than yours, and mine was not so bad after all. :-)
That said, perhaps I am not so ashamed to show the sophisticated method of building the RE, that coerces the RE engine into an optimization it should know about but does not (yet):
use strict; my $match = &ret_match_any( "0 OBS", "AT LEAST", "EXTRANEOUS", "CARTESIAN", "CLOSING", "CONVERT", "DIVISION BY ZERO", "DOES NOT EXIST", "DUE TO LOOPING", "END OF MACRO", "ENDING EXECUTION", "ERROR", "ERRORABEND", "ERRORCHECK=STRICT", "EXCEED", "HANGING", "HAS 0 OBSERVATIONS", "ILLEGAL", "INCOMPLETE", "INVALID", "LOST CARD", "MATHEMAT", "MERGE STATEMENT", "MISSING", "MULTIPLE", "NOT FOUND", "NOT RESOLVED", "OBS=0", "REFERENCE", "REPEAT", "SAS CAMPUS DRIVE", "SAS SET OPTION OBS=0", "SAS WENT", "SHIFTED", "STOP", "TOO SMALL", "UNBALANCED", "UNCLOSED", "UNREF", "UNRESOLVED", "WARNING" ); while(<>) { if ($_ =~ $match) { print "line $., file $ARGV, problem $1\n$_\n"; } } # Takes a list of strings and returns an RE that matches any. sub ret_match_any { my $match_str = &trie_strs(map quotemeta, @_); return qr /($match_str)/; } # Takes a list of escaped strings and returns a single string # suitable for building a match in an efficient way. # Works recursively by grouping strings that share one character sub trie_strs { unless (@_) { return (); } my %rest; foreach my $str (@_) { if (length($str)) { my $chr = substr($str, 0, 1); if ("\\" eq $chr) { $chr = substr($str, 0, 2); push @{$rest{$chr}}, substr($str, 2); } else { push @{$rest{$chr}}, substr($str, 1); } } else { $rest{''} = ['']; } } my @to_join; foreach my $chr (keys %rest) { my $list_ref = $rest{$chr}; if (1 < @$list_ref) { push @to_join, $chr . &trie_strs(@$list_ref); } else { push @to_join, $chr . $list_ref->[0]; } } if (1 < @to_join) { return '(?:' . (join '|', @to_join) . ')'; } else { return $to_join[0]; } }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
RE: RE (tilly) 4: SAS log scanner
by takshaka (Friar) on Sep 03, 2000 at 10:45 UTC | |
by tye (Sage) on Sep 04, 2000 at 00:01 UTC | |
by tilly (Archbishop) on Sep 03, 2000 at 18:08 UTC |