绿藻君的gps 2016-10-20 03:48 采纳率: 50%
浏览 3897
已结题

java中charAt()方法中字符串越界

目标:写一个micro词法分析器
问题:在读入写有micro代码文件的过程中,到最后一个字符(例如37)的时候报错。
报错信息:

 Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 37
    at java.lang.StringBuffer.charAt(Unknown Source)
    at Analyzer.getChar(Analyzer.java:34)
    at Analyzer.analyse(Analyzer.java:203)
    at Analyzer.main(Analyzer.java:231)

代码:

 //getChar()方法
public void getChar() {
ch = buffer.charAt(i);
i++;
}
//在主函数中
if (isLetter()) { // (一)如果ch为字母
                while (isLetter() || isDigit()) {
                    concat();
                    getChar();
                }
                //省略...
}

已更新全部代码:


import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Analyzer {

    private String keyWords[] = { "int", "begin", "end", "read", "write" }; // 关键字数组
    private char operators[] = { '=', '+', '-' }; // 运算符数组
    private char separators[] = { ',', ';', '(', ')' }; // 分隔符数组
    private String fileSrcName; // 源程序名
    private StringBuffer buffer = new StringBuffer(); // 缓冲区
    private char ch; // 字符变量,存放最新读进的源程序字符
    private static int i = 0;
    private static int ketType;// 作返回值,用于调用不同的打印的方法
    private String strToken; // 字符数组,存放构成单词符号的字符串

    public Analyzer() {
    }

    public Analyzer(String fileSrcName) {
        this.fileSrcName = fileSrcName;
    }

    /**
     * 将下一个输入字符读到ch中,搜索指示器前移一个字符 比如字符串的长度是6 但是每个字符的下标是从0开始计算 0 1 2 3 4 5
     * 所以charAt(i)中的i最大是字符串长度-1. 你在do while循环里有个i++,i 如果等于5的时候,在charAt(i)就明显越界了
     */
    public void getChar() {
        if (i < buffer.length()) {// i<6
            ch = buffer.charAt(i);
            if (i != buffer.length()-1) {
                i++;
            }
        }
    }

    /**
     * 检查ch中的字符是否为空白,若是则调用getChar() 直至ch中进入一个非空白字符
     */
    public void getBc() {
        while (Character.isSpaceChar(ch))
            getChar();
    }

    /**
     * 将ch连接到strToken之后
     */
    public void concat() {
        strToken += ch;
    }

    /**
     * 判断字符是否为字母
     */
    boolean isLetter() {
        return Character.isLetter(ch);
    }

    /**
     * 判断字符是否为数字
     */
    boolean isDigit() {
        return Character.isDigit(ch);
    }

    /**
     * 将搜索指示器回调一个字符位置,将ch值为空白字
     */
    public void retract() {
        i--;
        ch = ' ';
    }

    /**
     * 判断单词是否为关键字 [1,5]
     */
    public int isKeyWord() {
        ketType = -1;
        for (int i = 0; i < keyWords.length; i++) {
            if (keyWords[i].equals(strToken))
                ketType = i + 1;
        }
        return ketType;
    }

    /**
     * 判断是否为运算符 [6,9) 678
     */
    public int isOperator() {
        ketType = -1;
        for (int i = 0; i < operators.length; i++) {
            // 例如operators[]有 = + -,那么operators[1] = ‘+’
            // 如果调用此方法判断是否为+,则当前i遍历的0、1
            // 返回的种别码ketType为1+6=7
            // 符合一开始设定的种别码表
            if (ch == operators[i])
                ketType = i + 6;
        }
        return ketType;
    }

    /**
     * 判断是否为分隔符 [9,13) 9 10 11 12
     */
    public int isSeparators() {
        ketType = -1;
        for (int i = 0; i < separators.length; i++) {
            if (ch == separators[i])
                ketType = i + 9;
        }
        return ketType;
    }

    /**
     * 打印关键字strToken
     */
    public void insertKeyWords(String strToken) {
        // System.out.print("关键字,种别[1,5]");
        System.out.println("(" + ketType + "," + strToken + ")");
    }

    /**
     * 打印运算符ch
     * 
     */
    public void insertOperators(char ch) {
        // System.out.print("运算符,种别 [6,9)");
        System.out.println("(" + ketType + "," + ch + ")");
    }

    /**
     * 打印分隔符
     */
    public void insertSeparators() {
        // System.out.print("分隔符,种别 [9,13)");
        System.out.println("(" + ketType + "," + ch + ")");
    }

    // 打印常数strToken

    public void insertConst(String strToken) {
        int num = Integer.parseInt(strToken);
        // System.out.print("常数,种别13");
        System.out.println("(" + 13 + "," + strToken + ")");
    }

    /**
     * 打印标识符(ID)
     */
    public void insertId(String strToken) {
        // System.out.print("标识符,种别14");
        System.out.println("(" + 14 + "," + ch + ")");
    }

    /**
     * 将源程序读入到缓冲区中
     */
    public void readFile() {
        try {
            FileReader fis = new FileReader(this.fileSrcName);
            BufferedReader br = new BufferedReader(fis);
            String temp = null;
            while ((temp = br.readLine()) != null) {
                buffer.append(temp);
            }

        } catch (FileNotFoundException e) {
            System.out.println("源文件未找到!");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("读写文件出现异常!");
            e.printStackTrace();
        }
    }

    /**
     * 词法分析
     */
    public void analyse() {
        strToken = ""; // 置strToken为空串
        while (i < buffer.length()) {
            getChar();
            getBc();
            if (isLetter()) { // (一)如果ch为字母
                while (isLetter() || isDigit()) {
                    concat();
                    getChar();
                }
                retract(); // 回调
                if (isKeyWord() > 0) { // 如果是为关键字,则保留字
                    insertKeyWords(strToken);
                } else { // 否,则 符号
                    insertId(strToken);
                }
                strToken = "";
            } else if (isDigit()) { // (二)如果ch为数字
                while (isDigit()) {
                    concat();
                    getChar();
                }
                retract(); // 回调
                insertConst(strToken); // 是常数
                strToken = "";
            } else if (isOperator() > 0) { // 是运算符
                insertOperators(ch);
            } else if (isSeparators() > 0) { // 是分隔符
                insertSeparators();
            }
        }
    }

    public static void main(String[] args) {
        Analyzer alr = new Analyzer("./src/input.txt");// 文件路径
        alr.readFile();
        alr.analyse();
        /*
         * System.out.println("关键字,种别[1,5] 12345"); System.out.println(
         * "运算符,种别 [6,9) 678"); System.out.println("分隔符,种别 [9,13) 9 10 11 12 ");
         * System.out.println("常数,种别13"); //System.out.println("标识符(ID),种别14");
         */
    }
}
  • 写回答

6条回答 默认 最新

  • 章半仙 2016-10-20 03:58
    关注

    看不懂 为什么 为了两行代码建立一个 getChar函数;

    评论

报告相同问题?

悬赏问题

  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大
  • ¥15 import arcpy出现importing _arcgisscripting 找不到相关程序