使用Java的HTML词法分析器

时间:2014-02-02 05:14:33

标签: java html lexical-analysis

我是一名学生程序员,我正在尝试为我的一个计算机科学课程构建一个HTML代码的词法分析器,其输出应该是HTML代码的单个标记和词汇。但是当我编译并运行我的分析器时,输出似乎有问题。

根据HTML代码:

    <table>
    <tr><td>temp</td><td>temp2</td></tr>
    </table>

输出应为:

    TOKEN       LEXEME
    ------------------
    TAGIDENT    <table
    GTHAN       >
    TAGIDENT    <tr
    GTHAN       >
    TAGIDENT    <td
    GTHAN       >
    IDENT       temp
    ENDTAGHEAD  </
    IDENT       td
    GTHAN       >
    TAGIDENT    <td
    GTHAN       >
    IDENT       temp2
    ENDTAGHEAD  </
    IDENT       td
    GTHAN       >
    ENDTAGHEAD  </
    IDENT       tr
    GTHAN       >

目前,这是我的代码:

import java.io.*;
import java.util.*;

public class LexAnalyzer {
public static void main(String[] args) {
    try { 
        String input = "" , s = "";
        Token t;
        BufferedReader in = new BufferedReader(new FileReader(new        File("Sample.html")));
        while((s = in.readLine()) != null) {
            input += s;
        }
        System.out.println(input);
        System.out.println("TOKEN       LEXEME");
        System.out.println("------------------");
        ArrayList<Token> a = getToken(input);
        for(int i = 0; i < a.size(); i++) {
            System.out.println(a.get(i).getId() + "    " + a.get(i).getLexeme());
        }
    }

    catch(Exception e) {
        e.printStackTrace();
    }
}

public static ArrayList<Token> getToken(String input) {
    String lexeme = ""; //lexeme = TOKEN = ie. TAGIDENT
    Token t = null;
    ArrayList<Token> a = new ArrayList<Token>();
    for(int i = 0; i < input.length(); i++) {
        if(input.charAt(i) == '<') {
            lexeme += input.charAt(i); 
            i++;
            //case 1: if followed by ! < = COMMENT
            if(input.charAt(i) == '!') {
                lexeme += input.charAt(i);
                i++;
                while(input.charAt(i) != '>') {
                    lexeme += input.charAt(i);
                    i++;
                }
                input = input.substring(lexeme.length(), input.length());
            }

            //case 2: if followed by letter < = TAGIDENT
            else if(isALetter(input.charAt(i))) {
                lexeme += input.charAt(i);
                i++;
                while(input.charAt(i) != '>' && input.charAt(i) != ' ') {
                    lexeme += input.charAt(i);
                    i++;
                }
                t = new Token("TAGIDENT", lexeme);
                input = input.substring(lexeme.length(), input.length());
                a.add(t);
            }

            //case 3: if followed by number or space < = LTHAN
            else if((isANumber(input.charAt(i)))) {
                lexeme += input.charAt(i);
                i++;
                while(input.charAt(i) != '<' || input.charAt(i) == ' ') { 
                    lexeme += input.charAt(i);
                    i++;
                }
                t = new Token("LTHAN", lexeme);
                input = input.substring(lexeme.length(), input.length());
                a.add(t);
            }

            //case 4: if followed by / < = ENDTAGHEAD
            else if(input.charAt(i) == '/') {
                lexeme += input.charAt(i);
                i++;
                //case 5: after ENDTAGHEAD -> IDENT
                if(isALetter(input.charAt(i))) {
                    lexeme += input.charAt(i);
                    i++;
                    while(input.charAt(i) != '>') {
                        lexeme += input.charAt(i);
                        i++;
                    }
                    t = new Token("IDENT", lexeme);
                    input = input.substring(lexeme.length(), input.length());
                    a.add(t);
                }
                t = new Token("ENDTAGHEAD", lexeme);
                input = input.substring(lexeme.length(), input.length());
                a.add(t);
            }
        }

        else if(input.charAt(i) == '>') {
            lexeme += input.charAt(i);
            i++;
            t = new Token("GTHAN", lexeme);
            input = input.substring(lexeme.length(), input.length());
        }
    }
    return a;
}

public static boolean isALetter(char inputChar) {
    Boolean itIsALetter = false;
    if("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM".indexOf(inputChar) != -1) {
        itIsALetter = true;
    }
    return itIsALetter;
}

public static boolean isANumber(char inputChar) {
    Boolean itIsANumber = false;
    if("1234567890".indexOf(inputChar) != -1) {
        itIsANumber = true;
    }
    return itIsANumber;
}

}

令牌类:

public class Token {
    String id, lexeme;

    public Token(String id, String lexeme) {
        this.id = id;
        this.lexeme = lexeme;
    }

    public String getId() {
        return id;
    }

    public String getLexeme() {
        return lexeme;
    }
}

我的代码输出:

    TOKEN       LEXEME
    ------------------
    TAGIDENT    <table
    IDENT       <table>></td
    ENDTAGHEAD  <table>></td

有关如何修复代码的任何建议?非常感谢!

2 个答案:

答案 0 :(得分:1)

每当您阅读令牌时:

while(input.charAt(i) != '>' && input.charAt(i) != ' ') {
    lexeme += input.charAt(i);
    i++;
}

你应该在while循环之后再添加一行:

lexeme += input.charAt(i);

以便读取最后一个结束字符>。一旦你修复了代码中的所有这些位置(或者更好的是,重构你的代码并将其提取到外部辅助方法) - 你将获得完整的令牌。

答案 1 :(得分:1)

您没有完全迭代input String的内容,因为您正在使用substrings,递增计数器i并检查您的input length

实际上,根据您的代码,lexeme负责获取所需内容,您根本不必使用子字符串。但是,lexeme还会向自身添加数据,并且根据您的打印语句,您希望将各个元素显示为lexeme的一部分。

删除此内容:

input = input.substring(lexeme.length(), input.length());

在每个父条件开始时,不是递增lexeme,而是从头开始

lexeme = "" + input.charAt(i);

但是,在内部循环和条件中,您可能仍希望增加它。

另一方面是您没有编写代码来处理text内容(temp)。

修改

根据上述建议,我尝试使用更改后的XML代码,这里是更改后的getToken()

public static ArrayList<Token> getToken(String input) {
        String lexeme = ""; // lexeme = TOKEN = ie. TAGIDENT
        Token t = null;
        ArrayList<Token> a = new ArrayList<Token>();

        for (int i = 0; i < input.length(); i++) {
            if (input.charAt(i) == '<') {
                lexeme = "" + input.charAt(i);
                i++;
                // case 1: if followed by ! < = COMMENT
                if (input.charAt(i) == '!') {
                    lexeme += input.charAt(i);
                    i++;
                    while (input.charAt(i) != '>') {
                        lexeme += input.charAt(i);
                        i++;
                    }

                }

                // case 2: if followed by letter < = TAGIDENT
                if (isALetter(input.charAt(i))) {
                    lexeme += input.charAt(i);
                    i++;
                    while (input.charAt(i) != '>' && input.charAt(i) != ' ') {
                        lexeme += input.charAt(i);
                        i++;
                    }
                    t = new Token("TAGIDENT", lexeme);

                    a.add(t);
                }

                // case 3: if followed by number or space < = LTHAN
                if ((isANumber(input.charAt(i)))) {
                    lexeme = "" + input.charAt(i);
                    i++;
                    while (input.charAt(i) != '<' || input.charAt(i) == ' ') {
                        lexeme += input.charAt(i);
                        i++;
                    }
                    t = new Token("LTHAN", lexeme);

                    a.add(t);
                }

                // case 4: if followed by / < = ENDTAGHEAD
                if (input.charAt(i) == '/') {
                    lexeme = "" + input.charAt(i);
                    i++;
                    // case 5: after ENDTAGHEAD -> IDENT
                    if (isALetter(input.charAt(i))) {
                        lexeme += input.charAt(i);
                        i++;
                        while (input.charAt(i) != '>') {
                            lexeme += input.charAt(i);
                            i++;
                        }
                        t = new Token("IDENT", lexeme);

                        a.add(t);
                    }
                    t = new Token("ENDTAGHEAD", lexeme);

                    a.add(t);
                }

                if (input.charAt(i) == '>') {
                    lexeme = "" + input.charAt(i);
                    // i++;
                    t = new Token("GTHAN", lexeme);

                    a.add(t);
                }

            }

            else if (input.charAt(i) == '>') {
                lexeme = "" + input.charAt(i);
                i++;
                t = new Token("GTHAN", lexeme);

                a.add(t);
            }
            // System.out.println(temp);
        }
        return a;
    }

输出我得到的是:

TOKEN       LEXEME
------------------
TAGIDENT    <table
GTHAN    >
TAGIDENT    ><tr
GTHAN    >
TAGIDENT    ><td
GTHAN    >
IDENT    /td
ENDTAGHEAD    /td
GTHAN    >
TAGIDENT    ><td
GTHAN    >
IDENT    /td
ENDTAGHEAD    /td
GTHAN    >
IDENT    /tr
ENDTAGHEAD    /tr
GTHAN    >
IDENT    /table
ENDTAGHEAD    /table
GTHAN    >

不是确切的输出,但仍然可以获得所有元素,并且应该让你去。