Source of FileSearcher.java


  1: import java.io.File;
  2: import java.io.FileNotFoundException;
  3: import java.util.ArrayList;
  4: import java.util.HashMap;
  5: import java.util.List;
  6: import java.util.Map;
  7: import java.util.Scanner;
  8: import java.util.Set;
  9: import java.util.TreeSet;

 11: /**
 12:  * A program that uses a Map from Strings to Sets of Integers to do efficient
 13:  * searches of a text file.  Sadly, the search is for a single word at a time.
 14:  * Try it on THIS file!
 15:  * 
 16:  * @author Mark Young (A00000000)
 17:  */
 18: public class FileSearcher {

 20:     private static final Scanner KBD = new Scanner(System.in);

 22:     public static void main(String[] args) {
 23:         printIntroduction();
 24:         List<String> lines = readLines();
 25:         Map<String, Set<Integer>> locations = makeLocationMap(lines);
 26:         search(lines, locations);
 27:     }

 29:     /**
 30:      * Tell user what you do.
 31:      */
 32:     private static void printIntroduction() {
 33:         System.out.println("\n"
 34:                 + "This program lets you search a file.\n");
 35:     }

 37:     /**
 38:      * Get the file and read its lines.
 39:      */
 40:     private static List<String> readLines() {
 41:         // create required variables
 42:         String fileName;
 43:         List<String> contents = new ArrayList<>();

 45:         // get file name
 46:         System.out.print("Enter a file name: ");
 47:         fileName = KBD.nextLine();
 48:         
 49:         // try to read the file
 50:         try (Scanner file = new Scanner(new File(fileName))) {
 51:             
 52:             // file exists: read it
 53:             while (file.hasNextLine()) {
 54:                 contents.add(file.nextLine());
 55:             }
 56:         } catch (FileNotFoundException fnf) {
 57:             
 58:             // file not found: exit program
 59:             System.err.println("\nSorry, I can't open that file.");
 60:             System.exit(1);
 61:         }

 63:         return contents;
 64:     }

 66:     /**
 67:      * Make a map showing where each word is. The map generated uses each word
 68:      * present in the list as a key to a set of line numbers. The line numbers 
 69:      * correspond to the position in the given list. If a line number is in the
 70:      * set, then the word is on that line.
 71:      *
 72:      * The map is case insensitive, with the lower-case version of the word
 73:      * being used as the key.
 74:      *
 75:      * Lines are split on white-space and punctuation.
 76:      *
 77:      * NOTE: because the lines are split on punctuation, contractions are split
 78:      * into two parts -- so "doesn't" gets recorded as two words, "doesn" and
 79:      * "t". An exercise for the reader is to come up with a plan to replace
 80:      * contractions in a way that'd allow them to be handled better.
 81:      *
 82:      * @param lines the lines to make the map from.
 83:      * @return a map from words to the numbers of the lines it appears on.
 84:      */
 85:     private static Map<String, Set<Integer>> makeLocationMap(
 86:             List<String> lines
 87:     ) {
 88:         // create required variables
 89:         Map<String, Set<Integer>> result = new HashMap<>();
 90:         
 91:         // for each line in the file (saved in list of lines)
 92:         for (int lineNumber = 0; lineNumber < lines.size(); ++lineNumber) {
 93:             
 94:             // get the line
 95:             String line = lines.get(lineNumber);
 96:             
 97:             // break the line up on spaces and punctuation
 98:             for (String word : line.split("[\\s\\p{Punct}]+")) {
 99:                 
100:                 // save word in loswer case (for case insensitive search)
101:                 word = word.toLowerCase();
102:                 if (result.containsKey(word)) {
103:                     // we've already seen this word before: add to its set
104:                     result.get(word).add(lineNumber);
105:                 } else {
106:                     // haven't seen this word before: make a new set
107:                     Set<Integer> s = new TreeSet<>();
108:                     s.add(lineNumber);
109:                     result.put(word, s);
110:                 }
111:             }
112:         }
113:         return result;
114:     }

116:     /**
117:      * Repeatedly look for a word in the file.
118:      * 
119:      * @param lines the list of lines from the file.
120:      * @param locations the map from words to line numbers.
121:      */
122:     private static void search(
123:             List<String> lines,
124:             Map<String, Set<Integer>> locations
125:     ) {
126:         // create required variables
127:         String searchWord;
128:         Set<Integer> lineNumbers;
129:         
130:         // get the search word (ONE WORD ONLY!)
131:         System.out.print("\nEnter the word you'd like to find: ");
132:         searchWord = KBD.nextLine();
133:         
134:         // quit when there is no word
135:         while (!searchWord.equals("")) {
136:             
137:             // switch to lower case (for case insensitive search)
138:             searchWord = searchWord.toLowerCase();
139:             
140:             // check to see if it's there
141:             if (locations.containsKey(searchWord)) {
142:                 
143:                 // it's there: print out the lines (with numbers)
144:                 System.out.println("Your word appears in these lines: ");
145:                 lineNumbers = locations.get(searchWord);
146:                 for (int lineNo : lineNumbers) {
147:                     System.out.printf("%6d: %s%n",
148:                             lineNo, lines.get(lineNo));
149:                 }
150:             } else {
151:                 
152:                 // not there: report failure
153:                 System.out.println("Your word doesn't appear in any line.");
154:             }

156:             // get next search word
157:             System.out.print("\nEnter the word you'd like to find: ");
158:             searchWord = KBD.nextLine();
159:         }
160:     }

162: }