#!/usr/bin/perl # The Missing Textutils, Ondrej Bojar, obo@cuni.cz # http://www.cuni.cz/~obo/textutils # # Given a regexp, all the matching lines are put in front of the file and all # the rest is put below. It's like running 'grep' and 'grep -v'. Optionally a # blank line is inserted to separate the blocks. # # This tool is extremely handy when manually editing any text-based database. # # $Id: solve_first,v 1.11 2007/03/23 06:08:36 bojar Exp $ use strict; use Getopt::Long; my $sort = 0; my $delim = 0; my $usecol = 0; my $inverse = 0; my $just_matching = 0; my $blockwise = 0; my $insens = 0; my $usage = 0; my $utf = 0; my $skip = 0; GetOptions("sort" => \$sort, "delim" => \$delim, "col=i"=>\$usecol, "inverse" => \$inverse, "blockwise" => \$blockwise, "insens"=>\$insens, "help"=>\$usage, "utf"=>\$utf, "skip=i"=>\$skip, "just-matching" => \$just_matching, ) or exit 1; $usecol --; if ($utf) { binmode(STDIN, ":encoding(utf8)"); binmode(STDOUT, ":encoding(utf8)"); } else { binmode(STDIN, ":encoding(iso-8859-2)"); binmode(STDOUT, ":encoding(iso-8859-2)"); } my $re = shift; if (!$re || $usage) { print STDERR "usage: solve_first options: --sort ... the top lines are sorted by \$1 of the reg. expression --delim ... add a blank line between the two parts --col=i ... check only the given column to check the reg. expression --inverse ... put above if not matches --blockwise ... match whole blocks of input instead of lines --just-matching ... do not print nonmatching blocks/lines --insens ... case insensitive --skip= "; exit 1; } while ($skip > 0) { my $l = <>; print $l; $skip --; } my %head; my $stack = ""; my $block = ""; while (($_ = <>) || $block ne "") { if ($blockwise) { $block .= $_; next if ! /^$/ && !eof(STDIN); } else { $block = $_; } my $test; if ($usecol > -1) { my @line = split /\t/, $block; $test = @line[$usecol]; } else { $test = $block; } my $result = $insens ? $test =~ /$re/moi : $test =~ /$re/om; if ($result xor $inverse) { if ($sort) { my $k = $1; if (defined $head{$k}) { $head{$k} .= $block; } else { $head{$k} = $block; } } else { print $block; } } else { $stack .= $block; } $block = ""; } if ($sort) { for my $k (sort {$a <=> $b} keys %head) { print $head{$k}; } } if (!$just_matching) { print "\n" if $delim; print $stack; }