使用java进行erlang字符解析

本文介绍了一种解析Erlang特有数据结构的方法,包括类({}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

与公司后端对接的时候erlang工程师经常丢过来这样一串字符串

{{1,7,[1,[2,3]]},3}"

或是这样一串

[{1,7,[1,[2,3]]},3]"

有点类似json又不是json,因为括号会出现多次也不适合用正则解析。这种情况怎么办呢?

解决方案如下:

1.观察规律:

每个括号是一对对存在 ’[‘对应‘]’,表示包含一个数组,‘{’对应'}',表示包含一个类,最前面的括号对应最后面的括号,考虑使用栈进行括号匹配

类或数组没有明确指明字段名,也可能出现 有字段名的(暂时无此需求,本文代码只针对无字段名形式的,后续有遇到会进行文章更新),定义一个erlangObject的类,可以往里面存数组或者类,若无指定字段则从1开始做为编号做属性名

2.代码实现:

先定义ErlangObject类,这里我使用了一个map保存属性,假设一个object是一个map,属性名是map的key,属性值就是key对应的值

import com.alibaba.fastjson.JSONException;
​
import java.util.HashMap;
import java.util.Map;
​
/**
 * erlang虚拟对象
 */
public class ErlangObject {
    Map<String,Object> map ;
​
    public ErlangObject(){
        map = new HashMap<>();
    }
​
    public void putString(String key,String data){
        map.put(key,data);
    }
​
    public String getString(String key,String data){
        if (map.containsKey(key)){
            return map.get(key).toString();
        }else {
            return data;
        }
​
    }
​
    public void put(String key,Object data){
        map.put(key,data);
    }
​
    public Object get(String key){
        if (map.containsKey(key)){
            return map.get(key);
        }else {
            return null;
        }
​
    }
​
    @Override
    public String toString() {
        return map.toString();
    }
}
复制代码

接下来是主要的转换类,这里使用单例加载。enClass就是解析类,enList就是解析数组。

两种思路差不多,enClass将{}里面的字符一个个遍历,遇到逗号则把遍历到的字符拼成字符串填入erlangObjet的一个属性(当出现括号{与[时,会将符号压入栈,表示这后面一段字符串是一个类或者数组的属性,在出现该括号对应的结束符之前会忽略逗号,出现对应逗号后,在解析这段数据写入erlangObjetobject)

enClass将[]里面的字符一个个遍历,遇到逗号则把遍历到的字符拼成字符串填入数组(当出现括号{与[时,会将符号压入栈,表示这后面一段字符串是一个类或者数组的属性,在出现该括号对应的结束符之前会忽略逗号,出现对应逗号后,再解析这段数据填入数组)

import java.util.*;
​
/**
 * erlang转换工具
 */
public class ErlangManager {
    // pair以右括号为key, 左括号为值
    private Map<Character, Character> pair = null;
​
    private static ErlangManager erlangManager;
​
    private ErlangManager()
    {
        pair = new HashMap<Character, Character>();
       // pair.put(')', '(');
        pair.put('}', '{');
        pair.put(']', '[');
    }
​
    public static ErlangManager getInstance(){
        if (erlangManager==null){
            erlangManager = new ErlangManager();
        }
        return erlangManager;
    }
​
​
    /**
     *  转为erlang类
     *  {}
     * @param s
     * @return
     * @throws ErlangParseException
     */
    public ErlangObject enClass(String s) throws ErlangParseException{
        if (s==null) throw new ErlangParseException();
        s = s.replace("\n","").replace("\r","").replace(" ","");
        //不是 {}格式则抛出异常
        if (!s.startsWith("{")||!s.endsWith("}")) throw new ErlangParseException();
        //长度为2则是空内容
        if (s.length()==2) s = "";
        //否则去掉两边括号
        else s = s.substring(1,s.length()-1);
        //用临时栈存储括号
        Stack<Character> sc = new Stack<Character>();
        //定义一个erlangObject节点
        ErlangObject erlangObject = new ErlangObject();
        StringBuilder sb = new StringBuilder();
        int keyindex = 1;  //当前无返回属性名,从1开始做为编号做属性名
        for (int i = 0; i < s.length(); i++)
        {
            Character ch = s.charAt(i);
            //遇到逗号如果栈是空的,就存为一个属性,否则当当前属性的内容
            if (ch==','&&sc.empty()){
                //递归存储erlang对象
                erlangObject.put(keyindex + "",getObject(sb.toString()));
                keyindex++;
                sb.delete( 0, sb.length() );
                continue;
            }
            sb.append(ch);
            if (pair.containsValue(ch))// 如果是左括号,放⼊栈中
            {
                sc.push(ch);
            } else if (pair.containsKey(ch)&&!sc.empty()&&sc.peek() == pair.get(ch)) // 如果匹配到对应的右括号就出栈
            {
                sc.pop();
            }
            //读取完字符串把最后一个数据放入虚拟erlang对象
            if (i == s.length()-1){
                erlangObject.put(keyindex + "",getObject(sb.toString()));
            }
        }
        return erlangObject;
    }
​
    /**
     * 转为object数组
     * []
     * @param s
     * @return
     * @throws ErlangParseException
     */
    public List<Object> enList(String s) throws ErlangParseException{
        if (s==null) throw new ErlangParseException();
        s = s.replace("\n","").replace("\r","").replace(" ","");
        if (!s.startsWith("[")||!s.endsWith("]")) throw new ErlangParseException();
        if (s.length()==2) s = "";
        else s = s.substring(1,s.length()-1);
        Stack<Character> sc = new Stack<Character>();
        List<Object> erlangObjectList = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++)
        {
            Character ch = s.charAt(i);
            if (ch==','&&sc.empty()){
​
                erlangObjectList.add(getObject(sb.toString()));
                sb.delete( 0, sb.length() );
                continue;
            }
            sb.append(ch);
            if (pair.containsValue(ch))// 如果是左括号,放⼊栈中
            {
                sc.push(ch);
            } else if (pair.containsKey(ch)&&!sc.empty()&&sc.peek() == pair.get(ch)) // 如果是右括号
            {
                sc.pop();
            }
            if (i == s.length()-1){
                erlangObjectList.add(getObject(sb.toString()));
            }
        }
        return erlangObjectList;
    }
​
​
    /**
     * 通过字符串前缀获取object
     * @param str
     * @return
     */
    private Object getObject(String str){
        try {
            if (str.startsWith("{")) {
                return enClass(str);
            } else if (str.startsWith("[")) {
                return enList(str);
            } else {
                return str;
            }
        }catch (Exception e){
            return str;
        }
    }
}
复制代码

还要为我们的转换定制一个异常

/**
 * Created by dengzhenli on 2019/1/5.
 * erlang定制异常
 */
public class ErlangParseException extends RuntimeException {
​
    private static final long serialVersionUID = 1L;
​
    public ErlangParseException(){
        super();
    }
​
    public ErlangParseException(String message){
        super(message);
    }
​
    public ErlangParseException(String message, Throwable cause){
        super(message, cause);
    }
}
复制代码

测试一下

public class ErTest {
​
    public static void main(String[] args) {
//
        ErlangManager judger =  ErlangManager.getInstance();
        try {
           System.out.println(judger.enClass(null));
            System.out.println(judger.enClass("{{1,7,[1,[2,3]]},3}"));
            System.out.println(judger.enClass("{player_yaodan,11166672,885,[{yaodan,809,35,1,1600,[]},{yaodan,795,47,1,1600,[]},{yaodan,827,90,1,1600,[]},{yaodan,829,29,1,1600,[]},{yaodan,819,66,1,1600,[]},{yaodan,733,41,1,1600,[]},{yaodan,738,11,1,1600,[]},{yaodan,745,78,1,1600,[]},{yaodan,747,5,1,1600,[]},{yaodan,751,47,1,1600,[]},{yaodan,679,90,1,1600,[]},{yaodan,692,96,1,1600,[]},{yaodan,494,96,1,1600,[]}],[],[],400,[2,5,1],true}"));
        }catch (Exception e){
            e.printStackTrace();
        }
​
    }
​
​
}
复制代码

运行结果如下,可看到成功解析出了我们想要的格式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值