本版的改进主要在字符串的处理,前版不允许出现[]{},:等,现在都可以了,做出的修改主要在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. 眼见为实 — CSS的overflow属性

    1. overflow属性 CSS的overflow属性指定当内容溢出一个元素的框,会发生什么.举个栗子: <!DOCTYPE html> <html> <head> ...

  2. 10、Java 数组的定义和使用

    1.数组的定义 首先举一个小例自:如果你现在需要定义100个int类型的变量,那么按照前俩节的做法为: int a = 1, b=2 , c=3.......; 可以发现我们的代码特别的冗余,而且不美 ...

  3. DB2 SQL Error: SQLCODE=-1585, SQLSTATE=54048

    DB2 执行SQL报错: DB2 SQL Error: SQLCODE=-1585, SQLSTATE=54048 你建的db2数据库没有建足够大的临时表空间,新建一个足够大的临时表空间 1.创建数据 ...

  4. C#LeetCode刷题之#830-较大分组的位置(Positions of Large Groups)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3750 访问. 在一个由小写字母构成的字符串 S 中,包含由一些连 ...

  5. [Hadoop] mapper数量的控制

    确定map任务数时依次优先参考如下几个原则: 1)      每个map任务使用的内存不超过800M,尽量在500M以下 比如处理256MB数据需要的时间为10分钟,内存为800MB,此时如果处理12 ...

  6. 在Linux使用虚拟环境

    定义 “虚拟环境”,是python解释器的一个私有副本.在这个环境中,你可以安装私有包,而且不会影响系统中安装的全局python解释器. 作用 为每个程序单独创建虚拟环境时,可以保证程序只能访问虚拟环 ...

  7. SpringBoot---SpringMVC关于拦截器的一些问题总结

    SpringBoot---SpringMVC关于拦截器的一些问题总结 环境: IDEA :2020.1 Maven:3.5.6 SpringBoot: 2.3.2 1.直接在地址栏输入 http:// ...

  8. Shell脚本之for循环语句的应用

    在实际工作中,经常会遇到某项任务需要多次执行的情况,而每次执行时仅仅是处理的对象不一样,其他命令相同.这时候可以使用for循环语句,针对不同的取值重复执行相同的命令序列. for循环语句的语法结构: ...

  9. PythonCrashCourse 第三章习题

    PythonCrashCourse 第三章习题 3.1 将一些朋友的姓名存储在一个列表中,并将其命名为names.依次访问该列表中的每个元素,从而将每个朋友的姓名都打印出来 names = ['lih ...

  10. 用python实现实时监控网卡流量

    很多时候,我们是需要查看服务器的网卡当前跑了多大流量,但对于网卡流量的查询,在linux下似乎没有像top那样的原生命令.虽然top功能很强大,可以实时查看cpu.内存.进程的动态,但是却没有对网卡流 ...