174Java解析文件名中的方括号表达式

Posted zhangchao19890805

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了174Java解析文件名中的方括号表达式相关的知识,希望对你有一定的参考价值。

1. 使用场景

在由不同编程语言构成的系统中,经常会出现下面的场景:一开始某个子系统(非Java编写)在硬盘上生成了某个二进制文件,下一步交给Java代码进行处理。并且文件的一些附加信息会保存在文件名中。

比如【173】VS2022调试通过海康温度报警SDK的C++代码 中生成的文件,文件名就用英文方括号 [] 来显示不同的信息。

例如

FireAlarm[192.168.1.56][20220107153455][101.5][0].jpg

第一个方括号表示IP。
第二个方括号表示日期时间。
第三个方括号表示温度。
第四个方括号表示测温单位: 0- 摄氏度(℃),1- 华氏度(℉),2- 开尔文(K)。
其中如果数值为空,就用空的方括号表示。

对应的图片文件生成后,就需要Java来对文件做进一步处理,并读取和文件相关的一系列参数加以处理。

那么,怎么用Java来读取文件名中的数据呢?这就是下一节讨论的内容。

2. 解析方括号

我把文件名看作程序的输入参数,参数类型是字符串。我同时也把文件名看作表达式。下文用表达式来指代文件名。
Java代码使用了 Parser 的方式来编写代码。 因为这个表达式逻辑比较简单,所以就没有使用巴科斯范式(BNF)。

整个代码结构如下:

其中Main类包含main方法,做测试用。

包 zhangchao.parser是用来解析表达式的包。其中只有 Parser 类的 getStrArr 方法是对外提供的公共方法。

2.1 单词(token)

表达式是由不同的单词(token)组成的。每个单词是一个或多个字符组成的集合。在这个例子中单词分成标识符单词(对应类IdToken)和标识符单词(对应类StrToken)。为了方便编程实现,我还加了个抽象类AbstractToken。继承关系如下图所示:

AbstractToken.java

package zhangchao.parser;

/**
 * 所有类型单词的抽象类
 * @author zhangchao
 */
abstract class AbstractToken 

    /**
     * 判断单词类型是不是字符串。
     * @return true是字符串,false不是字符串。
     */
    boolean isString() 
        return false;
    

    /**
     * 判断单词是不是标识符。
     * @return true是标识符,false不是标识符。
     */
    boolean isIdentifier() 
        return false;
    


    /**
     * 以字符串类型,返回单词内容
     * @return 单词的字符串内容
     */
    abstract String show();


IdToken.java

package zhangchao.parser;

/**
 * 标识符类型的单词
 *
 * @author zhangchao
 */
class IdToken extends AbstractToken 
    // 单词的值
    String value;

    @Override
    boolean isIdentifier() 
        return true;
    

    @Override
    String show() 
        return value;
    


StrToken.java

package zhangchao.parser;

/**
 * 字符串类型的单词
 * @author zhangchao
 */
class StrToken extends AbstractToken
    // 单词的值
    String value;

    @Override
    boolean isString() 
        return true;
    

    @Override
    String show() 
        return value;
    


2.2 词法分析器Lexer

词法分析器Lexer负责把表达式拆成多个单词。

Lexer.java

package zhangchao.parser;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 词法分析器
 * @author zhangchao
 */
class Lexer 

    // 保存单词
    private ArrayList<AbstractToken> queue = new ArrayList<AbstractToken>();


    /**
     * 预读取表达式。
     * 从index给定的位置开始,计算字符串类型的单词的长度。
     *
     * @param arr  表达式转化成的字符数组。
     * @param index 从数组中index位置开始,计算字符串类型的单词的长度。
     * @return 字符串类型的单词的长度。
     */
    private int preRead(char[] arr, int index) 
        int result = 0;
        for (int i = index; i < arr.length; i++) 
            char c = arr[i];
            if (c == '[') 
                break;
             else if (c == ']') 
                break;
             else 
                result ++;
            
        
        return result;
    

    /**
     * 解析输入的表达式字符串,并且解析成【单词Token】
     * @param str 输入的表达式字符串。
     */
    void addQueue(String str) 
        char[] arr = str.toCharArray();
        int length = arr.length;
        for (int i = 0; i < length;) 
            char c = arr[i];
            if (c == '[') 
                IdToken t = new IdToken();
                t.value = String.valueOf(c);
                queue.add(t);
                i++;
             else if (c == ']') 
                IdToken t = new IdToken();
                t.value = String.valueOf(c);
                queue.add(t);
                i++;
             else 
                int size = preRead(arr, i);
                char[] tmp = Arrays.copyOfRange(arr, i, i + size);
                StrToken strToken = new StrToken();
                strToken.value = new String(tmp);
                queue.add(strToken);
                i = i + size;
            
        
    

    /**
     * 因为只关心在 [] 中的字符串,所以不在 [] 中的 【单词】 都要删除
     */
    void delNonsenseToken() 
        int length = this.queue.size();
        if (0 == length) 
            return;
        
        for (int i = length - 1; i >= 0; i--) 
            AbstractToken t = queue.get(i);
            if (t.isString()) 
                // 开头或者结尾的字符串,肯定不在 [] 之中
                if (queue.size() - 1 == i || 0 == i) 
                    queue.remove(i);
                 else if (i - 1 >= 0) 
                    AbstractToken left = queue.get(i - 1);
                    if (left.isIdentifier() && left.show().equals("]")) 
                        queue.remove(i);
                    
                 else if (i + 1 < queue.size()) 
                    AbstractToken right = queue.get(i + 1);
                    if (right.isIdentifier() && right.show().equals("[")) 
                        queue.remove(i);
                    
                
             // end if (t.isString()) 
        
    



    List<AbstractToken> getQueue() 
        queue.trimToSize();
        return queue;
    




2.3 语法分析器Parser

语法分析器Parser负责解析单词,构造抽象语法树(AST)。类 AstNode 是抽象语法树的节点。

AstNode.java

package zhangchao.parser;

import java.util.List;
import java.util.ArrayList;

/**
 * 抽象语法树  AST 的节点
 * @author zhangchao
 */
class AstNode 

    List<AbstractToken> children = new ArrayList<>();

    String eval() 
        return children.get(1).show();
    


Parser.java

package zhangchao.parser;

import java.util.ArrayList;
import java.util.List;

/**
 * 语法分析器
 * @author zhangchao
 */
public class Parser 

    /**
     * 词法分析器
     */
    private Lexer lexer = new Lexer();


    /**
     * 对输入的字符串进行语法分析,生成抽象语法树AST。
     * @param str 输入的字符串
     * @return 抽象语法树节点AstNode列表。
     */
    private List<AstNode> parser(String str) 
        lexer.addQueue(str);
        lexer.delNonsenseToken();
        List<AbstractToken> queue = lexer.getQueue();

        ArrayList<AstNode> allNodes = new ArrayList<>();

        int size = queue.size();
        for (int i = 0; i < size; i++) 
            AbstractToken current = queue.get(i);
            AbstractToken add1 = null;
            AbstractToken add2 = null;
            if (i + 1 < size) 
                add1 = queue.get(i + 1);
            
            if (i + 2 < size) 
                add2 = queue.get(i + 2);
            

            if (current.isIdentifier() && current.show().equals("[") &&
                    null != add1 && add1.isIdentifier() && add1.show().equals("]")) 
                AstNode node = new AstNode();
                node.children.add(current);
                StrToken emptyToken = new StrToken();
                emptyToken.value = "";
                node.children.add(emptyToken);
                node.children.add(add1);
                allNodes.add(node);
            
            if (current.isIdentifier() && current.show().equals("[") &&
                    null != add1 && add1.isString() &&
                    null != add2 && add2.isIdentifier() && add2.show().equals("]")) 
                AstNode node = new AstNode();
                node.children.add(current);
                node.children.add(add1);
                node.children.add(add2);
                allNodes.add(node);
            
        
        allNodes.trimToSize();
        return allNodes;
    


    /**
     * 输入形如  COMM_ALARM_ACS_CapPic[0][20220107153455][36.099][192.168.1.1][].jpg  字符串,
     * 此方法会把 [] 中的内容提取出来,
     * 并用列表形式返回。对比Lexer,增强了对空括号的处理。
     * @param str 形如  COMM_ALARM_ACS_CapPic[0][20220107153455][36.099][192.168.1.1].jpg  字符串
     * @return 从[]中提取的字符串,组成的字符串列表
     */
    public List<String> getStrArr(String str) 
        List<AstNode> allNodes = this.parser(str);
        ArrayList<String> result = new ArrayList<>();
        for (AstNode node : allNodes) 
            result.add(node.eval());
        
        return result;
    


2.4 测试

Main.java

package zhangchao;

import zhangchao.parser.Parser;

import java.util.List;

/**
 * 主类,保护main方法。
 * @author zhangchao
 */
public class Main 


    public static void main(String[] args) 


        String name = "COMM_ALARM_ACS_CapPic[][20220107153455][36.099][37.69.15.243][].jpg";
        Parser p = new Parser();
        List<String> stringList = p.getStrArr(name);
        for (String str : stringList) 
            System.out.println("str=" + str);
        
    



输出结果:

str=
str=20220107153455
str=36.099
str=37.69.15.243
str=

以上是关于174Java解析文件名中的方括号表达式的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式在非常大的html文件中匹配java中的花括号[重复]

在Java中,设计一个算法,判断一个算术表达式中的括号是不是配对。

温度转换-java

从 XML 文件 (Java) 中的特定标签解析内容

java 使用正则表达式replace(redEx,replaceStr) 中遇到的问题

QT之计算器核心解析算法