Java Program to Make Changes Based on Dictionary

Here is a Java program that will make delimited text changes to an input file, based on a file of substitutions and producing a new output file with the changes. Here "delimited" means that only complete identifiers are changed, so that below "xyz" is to be changed to "abc", but "xyz123" and "xyz12" remain unchanged.


// Changes.java: apply a dictionary of changes to an input source file
//   and write out result as a new file
import java.io.*;
class Changes {

   // three files:
   private SimpleReader reader; // source file to be changed
   private ChangeTable changeTable; // class to hold table of changes
   private SimpleWriter writer; // file for changed source

   // Changes: constructor -- create ChangeTable, open input and output
   public Changes() {
      reader = new SimpleReader("source.txt"); // source for changes
      changeTable = new ChangeTable("changes.txt"); // create table of changes
      writer = new SimpleWriter("output.txt"); // changed file
   }

   // makeChanges: read the source file.  Find identifiers.
   //   substitute for the identifiers if one is found as an
   //   entry in the change file.  Copy rest of source to output
   public void makeChanges() {
      char ch; // input char
      String id = ""; // string to hold each identifier
      boolean inID = false; // are we inside an identifier?
      while ((byte)(ch = reader.getNextChar()) != -1) { // till EOF
         if (inID) { // inside an identifier (already found first char)
            if (Character.isJavaIdentifierPart(ch)) // inside identifier
               id += ch; // add current char to identifier
            else { // end of identifier in source
               inID = false; // now at end of identifier
               String newID = changeTable.lookUp(id);
               if (newID == null) writer.putNextString(id); // output old id
               else writer.putNextString(newID); // output substitute
               writer.putNextChar(ch); // don't forget ch just past id
            }
         }
         else if (Character.isJavaIdentifierStart(ch)) { // start of ident
            id = ch + ""; // ch starts a new identifier in the source
            inID = true; // now inside an identifier
         }
         else writer.putNextChar(ch);  // otherwise output ch
      }
      // flush output
      writer.flushWriter();
   }

   public static void main(String[] args) throws IOException {
      Changes changes = new Changes(); // create the Changes class
      changes.makeChanges(); // read file and make substitutions
   }
}

// Entry.java: entry in the ChangeTable class public class Entry { private String oldID; // old string, to be replaced private String newID; // new string, to use for replacing public Entry(String oldIdent, String newIdent) { oldID = oldIdent; newID = newIdent; } public String getOld() { return oldID; } public String getNew() { return newID; } }
// ChangeTable.java: table of text changes to make import java.io.*; public class ChangeTable { SimpleReader reader; private final int CHANGE_TABLE_SIZE = 100; // max table size private Entry[] changeTable; // the table of changes itself private int count; // number of current entries public ChangeTable(String fileName) { reader = new SimpleReader(fileName); // create reader for input count = 0; // start out with no entries changeTable = new Entry[CHANGE_TABLE_SIZE]; // allocate table buildChangeTable(); // read change entries and build table } // buildChangeTable: read the change input file and insert // changes into changeTable private void buildChangeTable() { while (true) { String oldStr = reader.getNextString(); // old string if (oldStr == null) break; // quit when get to EOF String newStr = reader.getNextString(); // new string if (newStr == null) { System.err.println("Inside ChangeTable, need pairs of strings"); System.exit(1); } insertEntry(oldStr, newStr); // insert new entry } } // insertEntry: add a single entry to changeTable private void insertEntry(String oldItem, String newItem) { changeTable[count++] = new Entry(oldItem, newItem); if (count == CHANGE_TABLE_SIZE) { // could add code here to double size System.err.println("Table Overflow"); System.exit(0); } } // lookUp: look up old string for possible replacement public String lookUp(String oldItem) { for (int i = 0; i < count; i++) if ( (changeTable[i].getOld()).equals(oldItem)) return changeTable[i].getNew(); // return replacemetn return null; // is case it's not there } public static void main(String[] args) { ChangeTable changeTable = new ChangeTable("changes.txt"); System.out.println(changeTable.lookUp("BaseConversion")); System.out.println(changeTable.lookUp("push")); System.out.println(changeTable.lookUp("baseConversion")); System.out.println(changeTable.lookUp("Baseconversion")); } }
// SimpleReader: fetch next char or string from file import java.io.*; public class SimpleReader { private Reader inFile; // file to read public SimpleReader(String fileName) { try { inFile = new FileReader(fileName); } catch (IOException e) { System.err.println("Exception opening file " + fileName); } } // getNextChar: fetches next char from inFile public char getNextChar() { char ch = ' '; // = ' ' to keep compiler happy try { ch = (char)inFile.read(); } catch (IOException e) { System.err.println("Exception reading character"); } return ch; } // getNextString: fetch String from inFile // delimited by whitespace public String getNextString() { char ch; String s = ""; while (true) { // skip inital whitespace ch = getNextChar(); if ((byte)ch == -1) return null; if (!Character.isWhitespace(ch)) break; } s += ch; // first char of string while (true) { // read non-whitespace chars ch = getNextChar(); if ((byte)ch == -1) return s; if (!Character.isWhitespace(ch)) s += ch; else break; } return s; } public static void main(String[] args) { SimpleReader reader = new SimpleReader("source.txt"); String s; char ch; // test reading strings one at a time until EOF (null string returned) while (true) { s = reader.getNextString(); if (s == null) break; System.out.println(s); } // test writing chars one at a time until EOF (-1 returned) /* while (true) { ch = reader.getNextChar(); if ((byte)ch == -1) break; System.out.print(ch); } */ } }
// SimpleWriter: fetch next char or string from file import java.io.*; public class SimpleWriter { private Writer outFile; // file to read public SimpleWriter(String fileName) { try { outFile = new FileWriter(fileName); } catch (IOException e) { System.err.println("Exception opening file " + fileName); } } // putNextChar: output next char to outFile public void putNextChar(char ch) { try { outFile.write((int)ch); } catch (IOException e) { System.err.println("Exception writing character"); } } // putNextString: output String to outFile public void putNextString(String s) { for (int i = 0; i < s.length(); i++) putNextChar(s.charAt(i)); } // flushWriter: flush outFile (must flush or close or both at end) public void flushWriter() { try { outFile.flush(); } catch (IOException e) { System.err.println("Exception flushing output"); } } // closeWriter: close outFile (must flush or close or both at end) public void closeWriter() { try { outFile.close(); } catch (IOException e) { System.err.println("Exception closing output"); } } public static void main(String[] args) { SimpleReader reader = new SimpleReader("source.txt"); SimpleWriter writer = new SimpleWriter("output2.txt"); String s; char ch; // test writing strings one at a time to EOF (null string returned) while (true) { s = reader.getNextString(); if (s == null) break; writer.putNextString(s + " "); } // test writing chars one at a time to EOF (65535 returned) /* while (true) { ch = reader.getNextChar(); if ((byte)ch == -1) break; writer.putNextChar(ch); } */ writer.flushWriter(); writer.closeWriter(); } }
Here is the output of a sample run, showing first the source file to be changed (source.txt), the file containing a dictionary of changes to make (changes.txt), and the output file that incorporates the changes (output.txt). The old identifier to be changed is shown in green and the new identifier to substitute for the old is shown in red.
// BaseConversion: convert to base 8
public class BaseConversion { 
   public int[] s = new int[100];
   public int top = 0;
   public int pop() { return s[--top]; }
   public void push(int n) { s[top++] = n; }
   public boolean empty() { return top == 0; }

   public void writebase(int n) {
      System.out.print(n + " in base 8 = ");
      while (n > 0) {
         push(n%8);
         n = n/8;
      }
      while (!empty())
         System.out.print(pop());
      System.out.println("(base 8)");
   }

   public static void main(String[] args) {
      BaseConversion baseConversion = new BaseConversion();
      baseConversion.writebase(93);
   }
}

BaseConversion ConvertToBase8 s myStack top stackTop pop popStack push pushStack n num empty emptyStack writebase writeBase baseConversion convertToBase8
// ConvertToBase8: convert to base 8 public class ConvertToBase8 { public int[] myStack = new int[100]; public int stackTop = 0; public int popStack() { return myStack[--stackTop]; } public void pushStack(int num) { myStack[stackTop++] = num; } public boolean emptyStack() { return stackTop == 0; } public void writeBase(int num) { System.out.print(num + " in base 8 = "); while (num > 0) { pushStack(num%8); num = num/8; } while (!emptyStack()) System.out.print(popStack()); System.out.println("(base 8)"); } public static void main(String[] args) { ConvertToBase8 convertToBase8 = new ConvertToBase8(); convertToBase8.writeBase(93); } }