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中,设计一个算法,判断一个算术表达式中的括号是不是配对。