本版的改进主要在字符串的处理,前版不允许出现[]{},:等,现在都可以了,做出的修改主要在Lexer类,另外Token类增加1了下标,TreeBuilder类的不合语法处也做出一定修改.

测试用例:https://www.cnblogs.com/heyang78/p/12956735.html

代码下载地址:https://files.cnblogs.com/files/heyang78/JsonAnalyzer2-20200525-2.zip

主要代码:

Token类,Json文本最终会被变成Token的链表:

package com.heyang;

/**
* Tokens in json format
* @author Heyang
*
*/
public class Token {
public static final int TYPE_OPEN_BRACE=0; // {
public static final int TYPE_CLOSE_BRACE=1; // }
public static final int TYPE_TEXT=2; // text
public static final int TYPE_COMMA=3; // ,
public static final int TYPE_COLON=4; // :
public static final int TYPE_OPEN_BRACKET=5; // [
public static final int TYPE_CLOSE_BRACKET=6; // ] private int type;
private String text;
private int index;// Used to remember location public Token(char c,int type) {
this.text=String.valueOf(c);
this.type=type;
} public Token(String word,int type) {
this.text=word;
this.type=type;
} public String toString() {
return String.format("token(text=%s,type=%d,index=%d)", text,type,index);
} public int getType() {
return type;
} public void setType(int type) {
this.type = type;
} public String getText() {
return text;
} public void setText(String text) {
this.text = text;
} public int getIndex() {
return index;
} public void setIndex(int index) {
this.index = index;
}
}

Lexer类,此类用于将json文本分成token:

package com.heyang;

import java.util.ArrayList;
import java.util.List; import org.apache.commons.lang.StringUtils; /**
* Parse json string to tokens
* @author Heyang
*
*/
public class Lexer {
private List<Token> tokens; public Lexer(String jsonTxt) {
tokens = new ArrayList<Token>(); String bundle = "";
for (int i = 0; i < jsonTxt.length(); i++) {
char c = jsonTxt.charAt(i); if(c==':') {
char t=c;
char p=t;
c=p;
} if (Character.isWhitespace(c)) {
continue;
} else if (c == '{') {
tokens.add(new Token(c, Token.TYPE_OPEN_BRACE));
} else if (c == '}') {
if (StringUtils.isNotEmpty(bundle)) {
tokens.add(new Token(bundle, Token.TYPE_TEXT));
bundle = "";
} tokens.add(new Token(c, Token.TYPE_CLOSE_BRACE));
} else if (c == '[') {
tokens.add(new Token(c, Token.TYPE_OPEN_BRACKET));
} else if (c == ']') {
if (StringUtils.isNotEmpty(bundle)) {
tokens.add(new Token(bundle, Token.TYPE_TEXT));
bundle = "";
} tokens.add( new Token(c, Token.TYPE_CLOSE_BRACKET));
} else if (c == ',') {
if (StringUtils.isNotEmpty(bundle)) {
tokens.add(new Token(bundle, Token.TYPE_TEXT));
bundle = "";
} tokens.add(new Token(c, Token.TYPE_COMMA));
} else if (c == ':') {
if (StringUtils.isNotEmpty(bundle)) {
tokens.add(new Token(bundle, Token.TYPE_TEXT));
bundle = "";
} tokens.add(new Token(c, Token.TYPE_COLON));
}else if(c == '\"') {
int idx=i+1; while(idx<jsonTxt.length()) {
char cEnd = jsonTxt.charAt(idx); if (cEnd == '\"') {
break;
} idx++;
} String sub=jsonTxt.substring(i, idx+1);
tokens.add(new Token(sub, Token.TYPE_TEXT));
i=idx;
} else {
bundle += c;
}
} setTokenIndexes();
} public void setTokenIndexes() {
int idx = 0;
for (Token t : tokens) {
idx++;
t.setIndex(idx);
}
} public void printTokens() {
int idx = 0;
for (Token t : tokens) {
idx++;
t.setIndex(idx);
System.out.println("#" + idx + " " + t.getText());
}
} public String getCompactJsonTxt() {
StringBuilder sb=new StringBuilder(); for (Token t : tokens) {
sb.append(t.getText());
} return sb.toString();
} public List<Token> getTokenList() {
return tokens;
}
}

Node类,代表json节点:

package com.heyang;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List; /**
* Json Node
* @author Heyang
*
*/
public class Node implements Comparable<Node>{ // There are value types
public static final int Type_String=1;
public static final int Type_Array=2;
public static final int Type_List=3; // Key always is String
private String key;
private Node parent; // There are three types of value
private int valueType;
private String valueString;
private List<Node> valueList; // indent depth
private int depth; public Node() { } public Node(String key,String value) {
this.key=key;
this.valueType=Type_String;
this.valueString=value;
this.depth=0;
} public Node(String key,int type) {
this.key=key;
this.valueType=type;
this.valueList=new LinkedList<Node>();
} public void addChild(Node child) {
if(valueList!=null) {
valueList.add(child);
child.parent=this; adjustDepth();
}
} private void adjustDepth() {
if(valueType==Type_List || valueType==Type_Array) {
for(Node json:valueList) {
json.depth=this.depth+1;
json.adjustDepth();
}
}
} public String toString() {
StringBuilder sb=new StringBuilder(); // key
String tabs=getIndentSpace();
sb.append(tabs); if(key!=null) {
sb.append(key);
sb.append(":");
} // value
if(valueType==Type_String) {
sb.append(valueString);
}else if(valueType==Type_Array) {
sb.append("[\n"); int n=valueList.size();
for(int i=0;i<n;i++) {
Node json=valueList.get(i);
if(i!=n-1) {
sb.append(json.toString()+",\n");
}else {
sb.append(json.toString()+"\n");
}
} sb.append(tabs+"]");
}else if(valueType==Type_List) {
sb.append("{\n"); Collections.sort(valueList); int n=valueList.size();
for(int i=0;i<n;i++) {
Node json=valueList.get(i);
if(i!=n-1) {
sb.append(json.toString()+",\n");
}else {
sb.append(json.toString()+"\n");
}
} sb.append(tabs+"}");
} return sb.toString();
} public int compareTo(Node other) {
return this.key.compareTo(other.key);
} private String getIndentSpace() {
return String.join("", Collections.nCopies(this.depth, " "));
} public String getKey() {
return key;
} public void setKey(String key) {
this.key = key;
} public Node getParent() {
return parent;
} public void setParent(Node parent) {
this.parent = parent;
} public List<Node> getValueList() {
return valueList;
}
}

TreeBuilder类,用于构建一棵Node节点树:

package com.heyang;

import java.util.List;

public class TreeBuilder {
private Node root;
private List<Token> tokens;
private int tokenIdx; public TreeBuilder(List<Token> tokens) throws Exception{
this.tokens=tokens;
this.tokenIdx=0; root=new Node(null,Node.Type_List);
parse_object(root);
} private void parse_object(Node parent) throws Exception{
Token token; token=fetchToken();
if(token.getType()!=Token.TYPE_OPEN_BRACE) {
throw new Exception("Expected:'{' actual:"+token.getText()+" "+token);
} for(;;) {
token=fetchToken();
if(token.getType()!=Token.TYPE_TEXT) {
returnToken();
break;
}
String key=token.getText(); token=fetchToken();
if(token.getType()!=Token.TYPE_COLON) {
throw new Exception("Expected:':' actual:"+token.getText()+" "+token);
} token=fetchToken();
if(token.getType()==Token.TYPE_TEXT) {
String value=token.getText();
parent.addChild(new Node(key,value));
}else if(token.getType()==Token.TYPE_OPEN_BRACE){
Node node=new Node(key,Node.Type_List);
parent.addChild(node);
returnToken();
parse_object(node);
}else if(token.getType()==Token.TYPE_OPEN_BRACKET) {
Node node=new Node(key,Node.Type_Array);
parse_array(node);
parent.addChild(node);
}else {
throw new Exception("value should be string/object/array but not.");
} token=fetchToken();
if(token.getType()==Token.TYPE_COMMA) {
continue;
}else {
returnToken();
break;
}
} token=fetchToken();
if(token.getType()!=Token.TYPE_CLOSE_BRACE) {
throw new Exception("Expected:'}' actual:"+token.getText()+" "+token);
}
} private void parse_array(Node parent) throws Exception {
Token token; for(;;) {
token=fetchToken();
if(token.getType()==Token.TYPE_TEXT) {
String value=token.getText();
Node node=new Node(null,value);
parent.addChild(node);
}else if(token.getType()==Token.TYPE_OPEN_BRACE) {
Node node=new Node(null,Node.Type_List);
parent.addChild(node); returnToken();
parse_object(node);
}else {
returnToken();
} token=fetchToken();
if(token.getType()==Token.TYPE_COMMA) {
continue;
}else {
returnToken();
break;
}
} token=fetchToken();
if(token.getType()!=Token.TYPE_CLOSE_BRACKET) {
throw new Exception("Expected:']' actual:"+token.getText()+" "+token);
}
} private Token fetchToken() {
if(tokenIdx>=tokens.size()) {
return null;
}else {
Token t=tokens.get(tokenIdx);
tokenIdx++;
return t;
}
} private void returnToken() {
if(tokenIdx>0) {
tokenIdx--;
}
} public Node getRoot() {
return root;
}
}

运行起来:

package com.heyang;

import com.heyang.util.BracketChecker;
import com.heyang.util.CommonUtil;
import com.heyang.util.Renderer; public class EntryPoint {
public static void main(String[] args) {
try {
// Read context from file
String jsonTxt=CommonUtil.readTextFromFile("C:\\hy\\files\\json\\01.json");
System.out.println("原文="+jsonTxt); // Is brackets balanced
BracketChecker checker=new BracketChecker();
boolean isBalanced=checker.isBalanced(jsonTxt);
if(isBalanced==false) {
System.out.println(Renderer.paintBrown(checker.getErrMsg()));
return;
} // Parse json to tokens
Lexer lex=new Lexer(jsonTxt);
//System.out.println("紧缩文本="+lex.getCompactJsonTxt());
//lex.printTokens(); // Build tree
TreeBuilder builder=new TreeBuilder(lex.getTokenList());
Node root=builder.getRoot();
System.out.println("内部排序后文本:\n"+root);
}catch(Exception ex) {
System.out.println(Renderer.paintBrown(ex.getMessage()));
ex.printStackTrace();
}
}
}

运行效果:

原文={    "type": "object",    "properties": {        "first_name": { "type": "string" },        "last_name": { "type": "string" },        "age": { "type": "integer" },        "club": {            "type": "object",            "properties": {                "name": { "type": "string" },                "founded": { "type": "integer" }            },            "required": ["name"]        }    },    "required": ["first_name", "last_name", "age", "club"]}
内部排序后文本:
{
"properties":{
"age":{
"type":"integer"
},
"club":{
"properties":{
"founded":{
"type":"integer"
},
"name":{
"type":"string"
}
},
"required":[
"name"
],
"type":"object"
},
"first_name":{
"type":"string"
},
"last_name":{
"type":"string"
}
},
"required":[
"first_name",
"last_name",
"age",
"club"
],
"type":"object"
}

--2020年5月25日--

JsonAnalyzer2 1.01版的更多相关文章

  1. 用于测试 JsonAnalyzer2 1.01版的测试用例

    14. 原文={"animal":"ca,t","color":"ora:nge","isMale" ...

  2. Node.js abaike图片批量下载Node.js爬虫1.01版

    //====================================================== // abaike图片批量下载Node.js爬虫1.01 // 1.01 修正了输出目 ...

  3. Node.js meitulu图片批量下载爬虫1.01版

    在 http://www.cnblogs.com/xiandedanteng/p/7614051.html 一文我曾经书写过一个图片下载爬虫,但原有程序不是为下载图片而设计故有些绕,于是稍微改写了一下 ...

  4. C语言实现二叉树-01版

    故事是这样开始的,项目经理有一天终于还是拍拍我肩膀说: 无论你的链表写得多么的好,无论是多么的灵活,我也得费老半天才查找到想要的数据: 这让我的工作非常苦恼,听说有一种叫做二叉树的数据结构,你看能不能 ...

  5. C语言实现单链表-01版

    单链表的应用非常广,它可以实现栈,队列等: Problem 我对学习任何东西都希望能找到尽可能简单的例子,而不是看起来好高大上的: 对链表这样简答的数据结构,有些书也是写得太过“完美”啦: 初学者很难 ...

  6. 9、Khala实现0.01版QQ

    这次来个有界面的. 登录界面: 主界面: 1.服务端开发: 只需创建一个类ChatType(./examples/HelloKhala/src/ChatType.cpp),在该类型中,核心为创建的两个 ...

  7. zw版·全程图解Halcon控件安装(delphi2007版)

    zw版·全程图解Halcon控件安装(delphi2007版) delphi+halcon,这个组合,可以说是图像分析的神级配置,无论是开发效率,还是运行实在是太高了,分分钟秒杀c+opencv,py ...

  8. C语言实现二叉树-02版

    ---恢复内容开始--- 昨天,提交完我们的二叉树项目后,今天早上项目经理早早给我打电话: 他说,小伙子干的不错.但是为什么你上面的insert是recusive的呢? 你难道不知道万一数据量大啦!那 ...

  9. C语言实现单链表-02版

    我们在C语言实现单链表-01版中实现的链表非常简单: 但是它对于理解单链表是非常有帮助的,至少我就是这样认为的: 简单的不能再简单的东西没那么实用,所以我们接下来要大规模的修改啦: Problem 1 ...

随机推荐

  1. AutoUpdater迁移到Github

    一. 摘要 最近一两年在做跨平台的解决方案,使应用程序能支持Android, iOS, Windows, MacOs. Linux等操作系统,在Android, iOS上可以使用Google Play ...

  2. C#LeetCode刷题之#852-山脉数组的峰顶索引(Peak Index in a Mountain Array)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4003 访问. 我们把符合下列属性的数组 A 称作山脉: A.le ...

  3. C#LeetCode刷题-双指针

    双指针篇 # 题名 刷题 通过率 难度 3 无重复字符的最长子串   24.5% 中等 11 盛最多水的容器   43.5% 中等 15 三数之和   16.1% 中等 16 最接近的三数之和   3 ...

  4. C#LeetCode刷题之#706-设计哈希映射(Design HashMap)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4116 访问. 不使用任何内建的哈希表库设计一个哈希映射 具体地说 ...

  5. HTTP PUT/POST/PATCH的区别

    幂等 idempotent 幂等操作的特定就是其任意多次执行所产生的影响与一次执行的影响相同 POST POST 用来创建一个新的数据 POST 不是幂等的, 意味着多次操作的结果是不同的, 多次操作 ...

  6. peewee的简单使用

    peewee的简单使用 peewee是一个轻量级的ORM框架,peewee完全可以应对个人或企业的中小型项目的Model层,上手容易,功能强大. 一.安装peewee模块 使用pip命令工具安装pee ...

  7. 结构体深度比较 reflect.DeepEqual

    demo1 package main import ( "fmt" "reflect" ) func main() { sliceMap1 := make([] ...

  8. c++右值引用和转移构造函数

    int &&i = ; //i绑定到了右值1 int b = ; cout << i << endl; //输出1 i = b; cout << i ...

  9. 个人项目wc(C语言)

    github地址:https://github.com/nilonger/mycangku 一.项目要求 1.wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写一个 ...

  10. 从 BIO、NIO 聊到 Netty,最后还要实现个 RPC 框架!

    大家好,我是 「后端技术进阶」 作者,一个热爱技术的少年. 觉得不错的话,欢迎 star!ღ( ´・ᴗ・` )比心 Netty 从入门到实战系列文章地址:https://github.com/Snai ...