Category: | Utility Scripts |
Author/Contact Info | /msg Aristotle |
Description: | Inspired by pudge over at use.perl, here's a short little script you can use to highlight pattern matches in input data. usage: hl [ -c colour ] [ -x ] pattern [ file... ] [ < input ] You can use capturing parens in your pattern. In that case, you can supply multiple attributes separated by commas, which will be used to individually colour the submatches. -x will supress lines without matches. Update: fixed massive offset calculation bug, hugely simplified the colourizing routine. Due to the semantics of the @- and @+ arrays, my first stab was a horrible monster and incredibly difficult to debug, far harder to write than it promised to be. The special entries at index 0 indicating the start and end of the entire match required terrible contortions to take into account. And, surprise surprise, the code was buggy. In fixing my bug, I realized that the proper special case looked almost like a common case. And then I realized that by appending a phantom zero-length match and changing index 0 to instead signify a phantom zero-length 0th match, both special cases disappear. Lesson: when implementing the semantics turns your brain to mush, change the semantics. For a history of the code, look at aforementioned use.perl thread. |
#!/usr/bin/perl use strict; use warnings; use Term::ANSIColor; use List::Util qw( min ); use Getopt::Std; getopts( 'c:x' ); my @color = split /,/, our $opt_c || 'bold red'; @ARGV or die <<"END_USAGE"; usage: @{[ colored( 'hl [ -c colour ] [ -x ] pattern [ file... ] [ < i +nput ]', 'bold' ) ]} You can use capturing parens in your pattern. In that case, you can supply multiple attributes separated by commas, which will be used to individually colour the submatches. @{[ colored( '-x', 'bold' ) ]} will supress lines without match +es. END_USAGE my $rx = shift; $rx = qr/$rx/; while ( <> ) { s{ $rx }{ colored_match() }gex or not( our $opt_x ) or next; print; } sub colored_match { my @START = @-; my @END = @+; my $last = min( $#color, $#START ); if ( $last ) { push @START, $END[ 0 ]; push @END, $END[ 0 ]; $END[ 0 ] = $START[ 0 ]; my $str; for my $i ( 0 .. $last ) { $str .= colored( substr( $_, $START[ $i ], $END[ $i ] - $START[ $i ] ), $color[ $i ], ) unless $i == 0; $str .= colored( substr( $_, $END[ $i ], $START[ $i + 1 ] - $END[ $i ] +), $color[ 0 ], ); } return $str; } else { return colored( substr( $_, $START[ 0 ], $END[ 0 ] - $START[ 0 ] ), $color[ 0 ], ); } } |
|
---|