BGrep.java Source code

Java tutorial

Introduction

Here is the source code for BGrep.java

Source

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.com/javaexamples3.
 */
//package je3.nio;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
 * BGrep: a regular expression search utility, like Unix grep, but
 * block-oriented instead of line-oriented. For any match found, the filename
 * and character position within the file (note: not the line number) are
 * printed along with the text that matched.
 * 
 * Usage: java je3.nio.BGrep [options] <pattern> <files>...
 * 
 * Options: -e <encoding> specifies and encoding. UTF-8 is the default -i
 * enables case-insensitive matching. Use -s also for non-ASCII text -s enables
 * strict (but slower) processing of non-ASCII characters
 * 
 * This program requires that each file to be searched fits into main memory,
 * and so does not work with extremely large files.
 */
public class BGrep {
    public static void main(String[] args) {
        String encodingName = "UTF-8"; // Default to UTF-8 encoding
        int flags = Pattern.MULTILINE; // Default regexp flags

        try { // Fatal exceptions are handled after this try block
            // First, process any options
            int nextarg = 0;
            while (args[nextarg].charAt(0) == '-') {
                String option = args[nextarg++];
                if (option.equals("-e")) {
                    encodingName = args[nextarg++];
                } else if (option.equals("-i")) { // case-insensitive matching
                    flags |= Pattern.CASE_INSENSITIVE;
                } else if (option.equals("-s")) { // Strict Unicode processing
                    flags |= Pattern.UNICODE_CASE; // case-insensitive Unicode
                    flags |= Pattern.CANON_EQ; // canonicalize Unicode
                } else {
                    System.err.println("Unknown option: " + option);
                    usage();
                }
            }

            // Get the Charset for converting bytes to chars
            Charset charset = Charset.forName(encodingName);

            // Next argument must be a regexp. Compile it to a Pattern object
            Pattern pattern = Pattern.compile(args[nextarg++], flags);

            // Require that at least one file is specified
            if (nextarg == args.length)
                usage();

            // Loop through each of the specified filenames
            while (nextarg < args.length) {
                String filename = args[nextarg++];
                CharBuffer chars; // This will hold complete text of the file
                try { // Handle per-file errors locally
                    // Open a FileChannel to the named file
                    FileInputStream stream = new FileInputStream(filename);
                    FileChannel f = stream.getChannel();

                    // Memory-map the file into one big ByteBuffer. This is
                    // easy but may be somewhat inefficient for short files.
                    ByteBuffer bytes = f.map(FileChannel.MapMode.READ_ONLY, 0, f.size());

                    // We can close the file once it is is mapped into memory.
                    // Closing the stream closes the channel, too.
                    stream.close();

                    // Decode the entire ByteBuffer into one big CharBuffer
                    chars = charset.decode(bytes);
                } catch (IOException e) { // File not found or other problem
                    System.err.println(e); // Print error message
                    continue; // and move on to the next file
                }

                // This is the basic regexp loop for finding all matches in a
                // CharSequence. Note that CharBuffer implements CharSequence.
                // A Matcher holds state for a given Pattern and text.
                Matcher matcher = pattern.matcher(chars);
                while (matcher.find()) { // While there are more matches
                    // Print out details of the match
                    System.out.println(filename + ":" + // file name
                            matcher.start() + ": " + // character pos
                            matcher.group()); // matching text
                }
            }
        }
        // These are the things that can go wrong in the code above
        catch (UnsupportedCharsetException e) { // Bad encoding name
            System.err.println("Unknown encoding: " + encodingName);
        } catch (PatternSyntaxException e) { // Bad pattern
            System.err.println("Syntax error in search pattern:\n" + e.getMessage());
        } catch (ArrayIndexOutOfBoundsException e) { // Wrong number of arguments
            usage();
        }
    }

    /** A utility method to display invocation syntax and exit. */
    public static void usage() {
        System.err.println("Usage: java BGrep [-e <encoding>] [-i] [-s]" + " <pattern> <filename>...");
        System.exit(1);
    }
}