[关闭]
@jimbo 2015-11-25T15:37:09.000000Z 字数 5352 阅读 734

一个很简单的括号语法检查器

1.实现效果

首先我们先看一下我们实现的效果是什么样子的。

我们要实现的功能如下,
1. 检查代码中括号的使用是否合法
2. 指出括号使用出现了什么错误
3. 指出哪个括号出现了问题,在行中找出他的位置

2.核心算法

核心算法并不是很复杂,如下

3.思路分析

我们首先按照算法理一下思路:
1. 我们要获取到文件里的字符信息,这里就要用到文件读写的内容;我打算包装一个ReadFile类,让他完成这些工作。
2. 对于这个程序我们关心的数据有括号、括号所在行号、括号所在行的内容以及括号在行里的位置;把这些数据封装成实体类SymbolEntity
3. 这检查过程中我们还需要产生错误信息,这个错误信息也需要包装成类ErrorDescription
4. 最后就是最核心的检查功能了,我们把他封装成CheckUtil类;这个类实现检测功能和错误信息生成功能;

4.具体实现

SymbolEntity.java类

  1. public class SymbolEntity {
  2. private String symbol;
  3. private int lineNumber;
  4. private String lineContent;
  5. private int symbolNumber;
  6. public SymbolEntity(String symbol, int lineNumber, String lineContent, int symbolNumber) {
  7. this.symbol = symbol;
  8. this.lineNumber = lineNumber;
  9. this.lineContent = lineContent;
  10. this.symbolNumber = symbolNumber;
  11. }
  12. public String getSymbol() {
  13. return symbol;
  14. }
  15. public int getLineNumber() {
  16. return lineNumber;
  17. }
  18. public String getLineContent() {
  19. return lineContent;
  20. }
  21. public int getSymbolNumber() {
  22. return symbolNumber;
  23. }
  24. }

ErrorDescription.java类

  1. public class ErrorDescription {
  2. private int errorLineNumber;
  3. private String errorDes;
  4. public ErrorDescription() {
  5. }
  6. public ErrorDescription(int errorLineNumber, String errorDes) {
  7. this.errorLineNumber = errorLineNumber;
  8. this.errorDes = errorDes;
  9. }
  10. public int getErrorLineNumber() {
  11. return errorLineNumber;
  12. }
  13. public String getErrorDes() {
  14. return errorDes;
  15. }
  16. public void setErrorLineNumber(int errorLineNumber) {
  17. this.errorLineNumber = errorLineNumber;
  18. }
  19. public void setErrorDes() {
  20. this.errorDes = errorDes;
  21. }
  22. }

CheckUtil.java类

  1. import java.util.Stack;
  2. import java.util.*;
  3. import java.io.IOException;
  4. //要注意在代码或者注释中出现的'{','}','(',')',也会影响我们的判断
  5. // { 123
  6. // } 125
  7. // ( 40
  8. // ) 41
  9. //故意出一个错误
  10. // {
  11. public class CheckUtil {
  12. private List<ErrorDescription> mErrorList = new ArrayList<>();
  13. private String mFileName;
  14. private ReadFile mReadFile;
  15. private Stack<SymbolEntity> mStack = new Stack();
  16. private boolean isOverCheck = false;
  17. public CheckUtil(ReadFile mReadFile) {
  18. this.mReadFile = mReadFile;
  19. mFileName = mReadFile.getFileName();
  20. }
  21. public CheckUtil(String mFileName) throws NullPointerException, Exception {
  22. this.mFileName = mFileName;
  23. mReadFile = new ReadFile(mFileName);
  24. }
  25. public boolean startCheck() throws IOException {
  26. String lineContent = "";
  27. while(null != (lineContent = mReadFile.next())) {
  28. for (int i = 0; i < lineContent.length(); i++) {
  29. switch(lineContent.charAt(i)) {
  30. case 123:
  31. mStack.push(new SymbolEntity(String.valueOf((char)123),
  32. mReadFile.getLineNumber(),
  33. lineContent,
  34. i+1));
  35. break;
  36. case 40:
  37. mStack.push(new SymbolEntity(String.valueOf((char)40),
  38. mReadFile.getLineNumber(),
  39. lineContent,
  40. i+1));
  41. break;
  42. case 125:
  43. dealChar((char)125, (char)123, lineContent, i+1);
  44. break;
  45. case 41:
  46. dealChar((char)41, (char)40, lineContent, i+1);
  47. break;
  48. }
  49. }
  50. }
  51. while (!mStack.isEmpty()) {
  52. SymbolEntity entity = mStack.pop();
  53. switch(entity.getSymbol().charAt(0)) {
  54. case 123:
  55. buildError(entity, (char)125);
  56. break;
  57. case 40:
  58. buildError(entity, (char)41);
  59. break;
  60. }
  61. }
  62. isOverCheck = true;
  63. if (0 == mErrorList.size()) {
  64. return true;
  65. } else {
  66. return false;
  67. }
  68. }
  69. private void dealChar(char currentChar, char oppositeSymbol, String lineContent, int symbolNumber) {
  70. if (!mStack.isEmpty()) {
  71. SymbolEntity entity = mStack.peek();
  72. if (entity.getSymbol().charAt(0) != oppositeSymbol) {
  73. buildError(new SymbolEntity(String.valueOf(currentChar),
  74. mReadFile.getLineNumber(), lineContent, symbolNumber), oppositeSymbol);
  75. } else {
  76. mStack.pop();
  77. }
  78. } else {
  79. buildError(new SymbolEntity(String.valueOf(currentChar),
  80. mReadFile.getLineNumber(), lineContent, symbolNumber), oppositeSymbol);
  81. }
  82. }
  83. private void buildError(SymbolEntity entity, char missSymbol) {
  84. //在什么什么文件里,第多少多少行的什么没有什么与之配对
  85. String result = "在" + mFileName + "中," + "第" + (entity.getLineNumber()+1) +
  86. "行的\"" + entity.getSymbol() + "\"没有\"" + missSymbol + "\"与之配对\n"
  87. + entity.getLineContent() + "\n";
  88. for (int i = 1; i < entity.getSymbolNumber(); i++) {
  89. result += " ";
  90. }
  91. result += "^";
  92. mErrorList.add(new ErrorDescription(
  93. entity.getLineNumber(),
  94. result)
  95. );
  96. }
  97. public boolean isChecked() {
  98. return isOverCheck;
  99. }
  100. public List<ErrorDescription> getErrorList() {
  101. if (isOverCheck) {
  102. return mErrorList;
  103. } else {
  104. return null;
  105. }
  106. }
  107. }

ReadFile.java类

  1. import java.io.*;
  2. public class ReadFile {
  3. //{
  4. private String mFileName; // file path
  5. private int mCurrentLine = 0; // current line number
  6. private BufferedReader mBufferReader; // read file class
  7. public ReadFile() {
  8. }
  9. public ReadFile(String mFileName) throws NullPointerException,Exception {
  10. if (null == mFileName) {
  11. throw new NullPointerException("file name is not allowed to be null");
  12. }
  13. if (!(new File(mFileName).isFile())) {
  14. throw new Exception("this filename is not a file");
  15. }
  16. this.mFileName = mFileName;
  17. mBufferReader = new BufferedReader(new
  18. FileReader(mFileName));
  19. }
  20. public String next() throws IOException {
  21. mCurrentLine++;
  22. return mBufferReader.readLine();
  23. }
  24. public int getLineNumber() {
  25. return mCurrentLine;
  26. }
  27. public String getFileName() {
  28. return mFileName;
  29. }
  30. }

Main.java类 该类就是来测试其他类

  1. import java.util.*;
  2. import java.io.*;
  3. import java.util.regex.*;
  4. public class Main{
  5. public static void main(String[] args) {
  6. File file = file = new File(".");
  7. final String regex = ".java";
  8. String[] list = file.list(new FilenameFilter() {
  9. @Override
  10. public boolean accept(File file, String name) {
  11. return name.contains(regex);
  12. }
  13. });
  14. Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
  15. String s = "";
  16. List<ErrorDescription> lists = new ArrayList<>();
  17. for (String name : list) {
  18. try {
  19. //System.out.println(name);
  20. ReadFile r = new ReadFile(name);
  21. CheckUtil c = new CheckUtil(r);
  22. if (c.startCheck()) {
  23. System.out.println(name +":没有错误");
  24. } else {
  25. lists.addAll(c.getErrorList());
  26. }
  27. } catch(Exception e) {
  28. System.out.println("出现未捕获的异常,信息如下:");
  29. e.printStackTrace();
  30. System.exit(-1);
  31. }
  32. }
  33. for (ErrorDescription e : lists) {
  34. System.out.println(e.getErrorDes());
  35. }
  36. }
  37. }
Created with Raphaël 2.1.2开始我的操作确认?结束yesno
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注