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

hi
i am using win32 GUI 1.06 with perl 5.10
in the following code i have a RichEdit control, i want to read a big file and to store it in @a array in which every element store one line.
then i want to find every occurences of 'be' pattern and to color it in Red color. my code are working fine, but if the 'be' occurrences are numerous and the file also is big, the process of coloring take too much time.
can someone please look how i could optimise the code?
Thanks
use Win32::GUI; use warnings; use strict; my $Win = new Win32::GUI::Window( -left => 3, -top => 5, -width => 640, -height => 480, -name => "Win", ); $Win->Show(); my $font = Win32::GUI::Font->new( -name => "Courier New", -size => 12, ); $Win->AddButton( -text => "Run", -name => "Button1", -left => 23, -top => 10, -width => 56, -height => 36, -foreground => 0, ); my $RichText = $Win->AddRichEdit( -text => "", -name => "RichText_Output", # OutPut Rich Text -left => 41, -top => 91, -width => 580, -height => 313, -multiline => 1, -vscroll => 1, ); $RichText->SetLimitText(4194304); Win32::GUI::Dialog(); sub Win_Terminate { return -1; } sub Button1_Click { my $file = "bigfile.txt"; my $onelineOfText; my @ptrns; my $outString; open(MYFILE, $file) || die; my @a = <MYFILE>; chomp @a; my $PATTERN = 'be'; for (@a) { $onelineOfText = $_; @ptrns = $onelineOfText =~ m/$PATTERN/g; if($ptrns[0]) { $outString = $outString . "$onelineOfText\r\n"; } } # print the lines containing patterns to RichText: $RichText->SetSel(-1,-1); # Move insertion point to the end $RichText->ReplaceSel($outString); #Insert at the insertion point # now the coloring process of just the matches: my $OutStrng = $RichText->Text(); #get the contents of RichText my @pstn; my $flag = 1; #get the positions of the beginning and end of every match: #and store them in a continious array @pstn while ($flag) { if($OutStrng =~ /$PATTERN/g){ push @pstn, $-[0]; push @pstn, $+[0]; } else {last} } my $x = 0; my $lng = $#pstn / 2; for(0..$lng){ $RichText -> SetSel($pstn[$x],$pstn[$x+1]); $RichText -> SetCharFormat( -color => "#FF0000"); $x = $x + 2; }; }

Replies are listed 'Best First'.
Re: coloring text in RichEdit takes long time
by BrowserUk (Patriarch) on Apr 18, 2008 at 14:45 UTC

    Try it this way:

    sub Button1_Click { open my $file, '<', "bigfile.txt" or die "$!"; ## One line at a time while( <$file> ) { ## skip it if it doesn't contain the text next unless m[be]; my @posns; ## Find the positions push @posns, [ $-[0], $+[ 0 ] ] while m[be]g; ## Get the current length my $oldLen = $RichText->TextLength; ## Move the seletion to the end and insert the line $RichText->SetSel( -1, -1 ); $RichText->ReplaceSel( $_ ); ## for each position found for( @posns ) { ## Set the selection to it, ## adjusting for the length of the previous contents $RichText->SetSel( map $oldLen + $_, @$_ ); ## And highlight it $RichText->SetCharFormat( -color => "#ff0000" ); } } close $file; }

    Ask if anything need clarifying.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: coloring text in RichEdit takes long time
by tachyon-II (Chaplain) on Apr 18, 2008 at 15:47 UTC

    Few comments. You need to use \b boundary condition to avoid higlighting say the "be" in because.

    The problem per se is that ReplaceSel is very slow and you hit it a lot.

    You can do the RTF formatting task very simply if you understand the format. Here is a sub that will highlight all the matches in a given text string and output RTF format data. It will only process TXT data, not existing RTF.

    # RGB format a text document using a highlight colour. # RGB 0-255 like HTML 0x00-0xFF # Output should be valid RTF but YMMV sub RTFhighlight { my ($text, $highlight, $r, $g, $b, $font) = @_; $font ||= "Arial"; $text =~ s/([\\{}])/\\$1/g; # escape \ and { } $text =~ s/\n/\\par\n/g; # convert \n to \par $text =~ s/\b\Q$highlight\E\b/\\cf1 $highlight\\cf0 /g; my $header = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fon +ttbl{\\f0\\fswiss\\fcharset0 $font;}}\n"; $header .= "{\\colortbl ;\\red$r\\green$g\\blue$b;}\n"; return $header.$text; } print RTFhighlight("hello be seabe be because", "be", 0, 0, 0xFF);

    To use it in your code just read in all the text in a single pass, highlight it, and set it. This is still a bit slow because of the ReplaceSel issue. You can get it to display chunks of the file by iterating over chunks of your file but the price is lots more calls to ReplaceSel so although you get the satisfaction of some output straight away it takes a lot longer to finish. This takes about 6 seconds to do 20,000 highlights in a 250k file on my el cheapo laptop. Creating the highlight text takes a few milliseconds, all the rest of the time we are waiting for ReplaceSel.

    One final note. You should delay showing the window until you have finished adding widgets. That way it will render properly when it appears ie move Win->Show.