zoukankan      html  css  js  c++  java
  • JsonAnalyzer2 1.01版

    本版的改进主要在字符串的处理,前版不允许出现[]{},:等,现在都可以了,做出的修改主要在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("[
    ");
                
                int n=valueList.size();
                for(int i=0;i<n;i++) {
                    Node json=valueList.get(i);
                    if(i!=n-1) {
                        sb.append(json.toString()+",
    ");
                    }else {
                        sb.append(json.toString()+"
    ");
                    }
                }
                
                sb.append(tabs+"]");
            }else if(valueType==Type_List) {
                sb.append("{
    ");
                
                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()+",
    ");
                    }else {
                        sb.append(json.toString()+"
    ");
                    }
                }
                
                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("内部排序后文本:
    "+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日--

  • 相关阅读:
    通过模板类简单实现Spark的JobServer
    aggregate 和 treeAggregate 的对比
    IntelliJ Idea 常用快捷键列表
    dataframe 数据统计可视化---spark scala 应用
    用java api读取HDFS文件
    .net Core 简单中间件使用
    .Net Core Ocelot网关使用熔断、限流 二
    .Net Core Ocelot网关使用 一
    Docker 问题处理
    CentOS 创建用户
  • 原文地址:https://www.cnblogs.com/heyang78/p/12956793.html
Copyright © 2011-2022 走看看