Now that we’ve seen how the
regular expressions package works,
it’s time to write Grep2
, a full-blown
version of the line-matching program with option parsing. Table 4-3 lists some typical
command-line options that a Unix
implementation of grep might include.
Table 4-3. Grep command-line options
We discussed the GetOpt
class back in Section 2.8. Here we use it to control the operation of an
application program. As usual, since main( )
runs
in a static context but our application main line does not, we could
wind up passing a lot of information into the constructor. Because we
have so many options, and it would be inconvenient to keep expanding
the options list as we add new functionality to the program, we use a
kind of Collection
called
a
BitSet
to pass all the true/false arguments: true
to print line numbers, false to print filenames, etc. (Collections
are covered in Chapter 7.) A BitSet
is much like a
Vector
(see Section 7.4) but is
specialized to store only boolean values, and is ideal for handling
command-line arguments.
The program basically just reads lines, matches
the pattern in them, and if a match is found (or not found, with
-v
), prints the line (and optionally some other
stuff too). Having said all that, the code is shown in Example 4-3.
Example 4-3. Grep2.java
import org.apache.regexp.*; import com.darwinsys.util.*; import java.io.*; import java.util.*; /** A command-line grep-like program. Some options, and takes a pattern * and an arbitrary list of text files. */ public class Grep2 { /** The pattern we're looking for */ protected RE pattern; /** The Reader for the current file */ protected BufferedReader d; /** Are we to only count lines, instead of printing? */ protected boolean countOnly = false; /** Are we to ignore case? */ protected boolean ignoreCase = false; /** Are we to suppress print of filenames? */ protected boolean dontPrintFileName = false; /** Are we to only list names of files that match? */ protected boolean listOnly = false; /** are we to print line numbers? */ protected boolean numbered = false; /** Are we to be silent bout errors? */ protected boolean silent = false; /** are we to print only lines that DONT match? */ protected boolean inVert = false; /** Construct a Grep object for each pattern, and run it * on all input files listed in argv. */ public static void main(String[] argv) throws RESyntaxException { if (argv.length < 1) { System.err.println("Usage: Grep pattern [filename...]"); System.exit(1); } String pattern = null; GetOpt go = new GetOpt("cf:hilnsv"); BitSet args = new BitSet( ); char c; while ((c = go.getopt(argv)) != 0) { switch(c) { case 'c': args.set('C'); break; case 'f': try { BufferedReader b = new BufferedReader pattern = b.readLine( ); b.close( ); } catch (IOException e) { System.err.println("Can't read pattern file " + System.exit(1); } break; case 'h': args.set('H'); break; case 'i': args.set('I'); break; case 'l': args.set('L'); break; case 'n': args.set('N'); break; case 's': args.set('S'); break; case 'v': args.set('V'); break; } } int ix = go.getOptInd( ); if (pattern == null) pattern = argv[ix-1]; Grep2 pg = new Grep2(pattern, args); if (argv.length == ix) pg.process(new InputStreamReader(System.in), "(standard input"); else for (int i=ix; i<argv.length; i++) { try { pg.process(new FileReader(argv[i]), argv[i]); } catch(Exception e) { System.err.println(e); } } } public Grep2(String arg, BitSet args) throws RESyntaxException { // compile the regular expression if (args.get('C')) countOnly = true; if (args.get('H')) dontPrintFileName = true; if (args.get('I')) ignoreCase = true; if (args.get('L')) listOnly = true; if (args.get('N')) numbered = true; if (args.get('S')) silent = true; if (args.get('V')) inVert = true; int caseMode = ignoreCase?RE.MATCH_CASEINDEPENDENT:RE.MATCH_NORMAL; pattern = new RE(arg, caseMode); } /** Do the work of scanning one file * @param patt RE Regular Expression object * @param ifile Reader Reader object already open * @param fileName String Name of the input file */ public void process(Reader ifile, String fileName) { String line; int matches = 0; try { d = new BufferedReader(ifile); while ((line = d.readLine( )) != null) { if (pattern.match(line)) { if (countOnly) matches++; else { if (!dontPrintFileName) System.out.print(fileName + ": "); System.out.println(line); } } else if (inVert) { System.out.println(line); } } if (countOnly) System.out.println(matches + " matches in " + fileName); d.close( ); } catch (IOException e) { System.err.println(e); } } }
Get Java Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.