Wednesday, 18 January 2017

Chapter 21 Exercise 10, Introduction to Java Programming, Tenth Edition Y. Daniel LiangY.

21.10 (Count the occurrences of each keyword)
Rewrite Listing 21.7 CountKeywords. java to read in a Java source code file
and count the occurrence of each keyword in the file, but don’t count the
keyword if it is in a comment or in a string literal.


import java.io.*;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.Collections;
import java.util.HashMap;
import java.util.Scanner;

public class Exercise_10 {


    public static void main(String[] args) {
        File file = new File("Exercise_10.java");
        if (!file.isFile()) {
            System.out.println(file + " is not a file");
            System.exit(0);
        }

        StringBuilder sb = null;
        try {
            byte[] bytes = Files.readAllBytes(file.toPath());
            sb = new StringBuilder(Charset.forName("UTF-8").decode(ByteBuffer.wrap(bytes)));
        } catch (IOException ex) {
            System.out.println("Error reading file.");
            ex.printStackTrace();
            System.exit(0);
        }
        filterString(sb);

        // Array of all Java keywords + true, false and null
        String[] keywordString = {"abstract", "assert", "boolean",
                "break", "byte", "case", "catch", "char", "class", "const",
                "continue", "default", "do", "double", "else", "enum",
                "extends", "for", "final", "finally", "float", "goto",
                "if", "implements", "import", "instanceof", "int",
                "interface", "long", "native", "new", "package", "private",
                "protected", "public", "return", "short", "static",
                "strictfp", "super", "switch", "synchronized", "this",
                "throw", "throws", "transient", "try", "void", "volatile",
                "while", "true", "false", "null"};

        HashMap<String, Integer> occurrences = new HashMap<>();

        for (String aKeywordString : keywordString) occurrences.put(aKeywordString, 0);

        String[] words = sb.toString().split("[()}\\{\\s+;=!,]");
        for (String word : words) {
            if (occurrences.containsKey(word)) {
                occurrences.put(word, occurrences.get(word) + 1);
            }
        }

        occurrences.forEach((k,v) -> System.out.println(k + " " + v));

    }

    private static void filterString(StringBuilder sb) {
        int startIndex = 0;
        while ((startIndex = resetToNextState(sb, startIndex) )!= -1) {
            if (states[IN_BLOCK])
                startIndex = removeBlockComment(sb, startIndex);
            else if (states[IN_LINE])
                startIndex = removeInlineComment(sb, startIndex);
            else if (states[IN_STRING])
                startIndex = removeStringLiteral(sb, startIndex);
            else if (states[IN_CHAR])
                startIndex = removeCharLiteral(sb, startIndex);
        }
    }

    private static int removeCharLiteral(StringBuilder sb, int startIndex) {
        return removeString(sb,  startIndex, tokens[IN_CHAR], "\\", INCLUSIVE);
    }

    private static int removeStringLiteral(StringBuilder sb, int startIndex) {
        return removeString(sb, startIndex,  tokens[IN_STRING], "\\", INCLUSIVE);
    }

    private static int removeInlineComment(StringBuilder sb, int startIndex) {
        return removeString(sb, startIndex, tokens[IN_LINE], "", KEEP_END);
    }

    private static int removeBlockComment(StringBuilder sb, int startIndex) {
        return removeString(sb,  startIndex, tokens[IN_BLOCK], "", INCLUSIVE);
    }


    private static final int INCLUSIVE = 0;
    private static final int EXCLUSIVE = 1;
    private static final int KEEP_START = 2;
    private static final int KEEP_END = 3;

    private static int removeString(StringBuilder sb, int startIndex, String[] tokens, String escapeToken, int options) {

        String startToken = tokens[0];
        String endToken = tokens[1];
        // Find the ending index
        int endIndex = sb.indexOf(endToken, startIndex + startToken.length()); // currently unknown

        // Check for any escape tokens
        if (escapeToken.length() > 0) {
            int escTokenIndex = startIndex;
            while (endIndex > (escTokenIndex = sb.indexOf(escapeToken, escTokenIndex)) && escTokenIndex != -1) {
                escTokenIndex += 2;
                endIndex = sb.indexOf(endToken, escTokenIndex);
            }
        }

        int startOffset = 0;
        int endOffset = 0;
        int finalIndex = startIndex; // Then new end index after the string is truncated
        switch (options) {
            case INCLUSIVE: // includes removal of both tokens
                endOffset = endToken.length();
                break;
            case EXCLUSIVE: // exclude tokens from being removed
                startOffset = startToken.length();
                finalIndex += startOffset + endToken.length();
                break;
            case KEEP_START: // keep only the start token
                endOffset = endToken.length();
                finalIndex += startToken.length();
                break;
            case KEEP_END: // keep only the ending token
                // Keep end is the default setting
                break;
        }

        if (endIndex < 0)
            endIndex = sb.length();

        sb.delete(startIndex + startOffset, endIndex + endOffset);
        return finalIndex;
    }


    // Used for indicating the current state
    private static boolean[] states = new boolean[4];
    // Possible states
    private static final int IN_LINE = 0; // line comment //
    private static final int IN_BLOCK = 1; // start with: /* */
    private static final int IN_STRING = 2; // string literal ""
    private static final int IN_CHAR = 3; // character literal ''
    // Tokens that trigger the beginning of a state
    private static final String[][] tokens = {{"//","\n"}, {"/*","*/",}, {"\"","\"",}, {"\'", "\'"}};

    private static int resetToNextState(StringBuilder sb, int startIndex) {

        // Reset the current state
        for (int i = 0; i < states.length; i++) {
            if (states[i])
                states[i] = false;
        }
        int key = -1;
        int nextStateIndex = -1;

        // Find the lowest value greater than -1
        for (int i = 0; i < tokens.length; i++) {
            int indexOf = sb.indexOf(tokens[i][0], startIndex);
            if (indexOf == -1) continue;
            if (indexOf < nextStateIndex || nextStateIndex == -1) {
                nextStateIndex = indexOf;
                key = i;
            }
        }

        if (key != -1)
            states[key] = true; // Set the current state
        return nextStateIndex;
    }
}

No comments :

Post a Comment