本版的改进主要在字符串的处理,前版不允许出现[]{},:等,现在都可以了,做出的修改主要在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. 一篇看懂Socket开发

    Socket[套接字]是什么,对于这个问题,初次接触的开发人员一般以为他只是一个通讯工具. Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发 T ...

  2. Nginx安装与运行配置总结

    Nginx安装与运行配置总结 1. 去官网下载对应的nginx包,推荐使用稳定版本 2. 上传nginx到linux系统 3. 安装依赖环境 (1)安装gcc环境 yun install gcc-c+ ...

  3. Hyperledger Fabric 部署

    Hyperledger Fabric 部署 Hyperledger Fabric需要使用Docker.Go环境. Docker环境安装 Docker环境安装 直接查看这一篇,安装好之后将当前用户非ro ...

  4. Vue 图片压缩上传: element-ui + lrz

    步骤 安装依赖包 npm install --save lrz 在main.js里引入 import lrz from 'lrz' 封装 compress函数 封装上传组件 upload-image ...

  5. 使用BERT进行情感分类预测及代码实例

    文章目录 0. BERT介绍 1. BERT配置 1.1. clone BERT 代码 1.2. 数据处理 1.2.1预训练模型 1.2.2数据集 训练集 测试集 开发集 2. 修改代码 2.1 加入 ...

  6. 关于python中Enum的个人总结

    关于python中Enum的个人总结 初识 可以通过enum模块导入 语法 初始化: 可以通过enum_ = Enum('class_name', names,start = 1)来创建,其中name ...

  7. python3 - 常用的操作数据库

    # 获取手机号数据表的中的数据 sql2 = 'SELECT shoujihao FROM shoujihao' self.cursor.execute(sql2) sjh_dates = self. ...

  8. CSS动画实例:升空的气球

    1.制作一个气球 设页面中有<div class="balloon"></div>,为. balloon设置样式规则如下: .balloon { heigh ...

  9. windows下Nacos集群搭建与nginx集成

    前言: nacos集群至少需要三个(一般为奇数个)nacos实 例,其前面顶nginx,外界入口从nginx入 一.windows下Nacos集群搭建 将Nacos的解压包复制分成3份,分别是: na ...

  10. 国人开源了一款超好用的 Redis 客户端,真香!!

    大家都知道,Redis Desktop Manager 是一款非常好用的 Redis 可视化客户端工具,但可惜的是 v0.9.4 版本之后需要收费了: 这个工具不再免费提供安装包了,要对所有安装包收费 ...