pl.xoft.saf.finder.Grep.java
package pl.xoft.saf.finder;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A very simple, grep-like tool to search for a given regular expression
 * in a file or files in directory.
 * 
 * The class simulates the following grep behaviour:
 * <pre>grep -n -e "regexp" -f filename(s)</pre>
 * 
 * @author Piotr Kochanski, http://www.xoft.pl
 */
public class Grep {
    
    private Pattern p = null;
    private Map<String, Map<Integer, String>> searchResults = new HashMap<String, Map<Integer, String>>();
    
    /**
     * Initialization
     * @param regex
     */
    public Grep(String regex){
        p =  Pattern.compile(regex);
    }
    
    /**
     * Determines if a specified regular expression was found in a given text. 
     * @param text text that will be scan for regular expression
     * @return <code>true</code> if the match was detacted 
     */
    private boolean isFound(String text){
        Matcher m = p.matcher(text);
        return m.find();
    }
    
    /**
     * <p>Looks for a given regular expression in a file or
     * directory and stores search results internally.</p> 
     * <p>Search results are available through {@link #getSearchResults} method</p>
     * TODO: skip by default binary files
     * 
     * @param f file or directory to be used as a search target
     * @throws java.io.FileNotFoundException
     * @throws java.io.IOException
     */
    public void searchInFiles(File f) throws FileNotFoundException, IOException{
        if(f.isDirectory()){
            File[] files = f.listFiles();
            for (int i = 0; i < files.length; i++) {
                searchInFiles(files[i]);
            }
        }else{
            BufferedReader bf = new BufferedReader(new FileReader(f));
            Map<Integer, String> results = new TreeMap<Integer, String>();
            int lineCounter = 1;
            String line;
            while((line = bf.readLine()) != null){
                if(isFound(line)){
                    results.put(lineCounter, line);
                }
                lineCounter++;
            }
            if(!results.isEmpty()){
                getSearchResults().put(f.getAbsolutePath(), results);
            }
            bf.close();
        }
    }
    
    /**
     * Returns the "double map" with search results. The resulting map has
     * the following structure:
     * <pre>
     * searchResultMap:
     *    (key: fileName, value: singleFileResultMap)
     * singleFileResultMap
     *    (key: lineNumber, value: lineContainingFoundToken)  
     * </pre>
     * @return map of maps with search result 
     */
    public Map<String, Map<Integer, String>> getSearchResults() {
        return searchResults;
    }
    
    /**
     * A convenience method. Retrives textual output, similar to that created by grep.
     * @see #getSearchResults
     * @return search results
     */
    public String getFormatedSearchResults(){
        StringBuilder sb = new StringBuilder();
        for (Iterator<String> it = getSearchResults().keySet().iterator(); it.hasNext();) {
            String fileName = it.next();
            for (Iterator<Integer> singleFileIt = getSearchResults().get(fileName).keySet().iterator(); singleFileIt.hasNext();) {
                Integer lineNumber = singleFileIt.next();
                sb.append(fileName + ":" + lineNumber + ":" + getSearchResults().get(fileName).get(lineNumber) + "\n");
            }
        }
        //remove last \n
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
    }
    
    /**
     * Usage example: 
     */
    public static void main(String[] args) throws FileNotFoundException, IOException {
        Grep g = new Grep("your regexp");
        File f = new File("your/file/name");
        g.searchInFiles(f);
        System.out.println(g.getFormatedSearchResults());
    }



}