如何在 Java 中使用字符堆栈验证 JSON 语法?

How to Validate JSON Syntax Using a Character Stack in Java?

我有一个输入文件 ("student.json"),它包含几行 JSON 代码,例如:

{"name":"Josh","age":22,"gender":"M"} 

将在 Java 程序中使用。程序应该输入文件,抓取一个 JSON 字符串,然后使用字符堆栈来验证语法(程序应该忽略具体的 属性 [name] 和值 [Josh] 是什么,但是知道每组大括号必须至少有 2 个值,中间有一个冒号)。如果语法正确,控制台会告诉用户 JSON 字符串有效,如果无效,控制台会告诉用户。

对于字符堆栈,我将遍历 JSON 字符串的每个字符。当遇到左大括号或方括号时,程序应将其压入堆栈。当遇到右大括号或括号时,程序应从堆栈中弹出一个值并查看它是否匹配。我还应该使用 isEmpty 方法来查看是否有不匹配的符号。

我以前从未使用过字符堆栈。我知道如何完成 Java 程序的其余部分,这只是我卡在的堆栈。

问题:如何使用此字符堆栈和要求验证 JSON 字符串?

是否绝对需要通过手动解析 JSON 来验证?如果不是,我建议使用 Jackson 的 ObjectMapper:http://fasterxml.github.io/jackson-databind/javadoc/2.2.0/com/fasterxml/jackson/databind/ObjectMapper.html#readTree(java.lang.String)

如果您尝试手动执行此操作,您将不得不担心嵌套对象和数组。

编辑:

堆栈

我假设您了解什么是堆栈 (LIFO) 的基础知识,但您有兴趣了解堆栈的底层实现方式。如果可以,请使用 Java LinkedList 作为底层数据结构。如果你必须使用一个简单的数组会更难,因为你将不得不处理调整大小并因此移动数组的所有元素。

使用 LinkedList,您只需为每次推送到堆栈添加 (E)/addFirst(E),然后为每次弹出添加 getLast()/getFirst()。

您可以在此 post 中找到示例:Stack array using pop() and push()

一个栈基本上就是这个接口:

public interface Stack<T> {
    void push(T item); // adds an item to the stack
    T peek(); // looks what is the last item in the stack
    T pop(); // removes and returns the last item of the stack
    boolean isEmpty(); // are there items in the stack?
}

这不是漂亮的代码,但这里有一个示例可以解决您的问题(使用内置 java.util.Stack class):

public static boolean isValid(String str) {
    Stack<Character> stack = new Stack<>();
    for (char c : str.toCharArray()) {
        switch (c) {
            case '{':
                stack.push(c);
                break;
            case '}':
                if (stack.isEmpty()) {
                    return false;
                }
                Character last1 = stack.pop();
                if (last1 != '{') {
                    return false;
                }
                break;
            case '\"':
                if (stack.isEmpty()) {
                    return false;
                }
                Character last2 = stack.peek();
                if (last2 == '\"') {
                    // It's a closing quote
                    stack.pop();
                } else {
                    // It's an opening quote
                    stack.push(c);
                }
                break;
        }
    }
    return stack.isEmpty();
}

有测试:

@Test public void isValid_if_true() {
    String jsonString = "{\"name\": \"John\"}";
    assertTrue(JsonValidator.isValid(jsonString));
}

@Test public void isValid_if_too_many_opened_brackets() {
    String jsonString = "{\"name\": \"John\", {}";
    assertFalse(JsonValidator.isValid(jsonString));
}

@Test public void isValid_if_too_many_closed_brackets() {
    String jsonString = "{\"name\": \"John\", }}";
    assertFalse(JsonValidator.isValid(jsonString));
}

@Test public void isValid_if_too_many_quotes() {
    String jsonString = "{\"name\": \"\"John\"}";
    assertFalse(JsonValidator.isValid(jsonString));
}

您仍然需要检查您的 JSON 对象中是否至少有 2 个属性,并验证 ,.

的位置

试着在纸上玩一下算法,看看它是如何工作的。

基本上我们忽略除括号和引号之外的所有字符。当我们得到其中一个特殊字符时,我们检查它们是否正在打开一个新的 "token"(压入堆栈)、关闭一个(从堆栈弹出)或者是否存在问题。

希望对您有所帮助。