基于字符流命令的内容解释
1、概述
我们常常需要解释ASCII码的输入流,这些输入流读入时一般是以字节数组的形式,这些输入还会包括命令或控制字符,对应不同的命令或控制字符都有不同的处理方式。而解释和匹配这些命令常常会令我们头痛。这里介绍一种方法可以有效的处理这些命令。
2、场景
以VT100 Terminal Control为例,这些控制命令是严谨的不会发生混淆的,他的命令有如:
<ESC>[c
<ESC>[{code}0c
<ESC>[{ROW};{COLUMN}R
<ESC>[{attr1};...;{attrn}m
<ESC>[{key};"{string}"p
3、分析
上面这些命令主要分为:
(I)明确的命令(<ESC>[c)
(II)定长可变的命令(<ESC>[{code}0c、<ESC>[{ROW};{COLUMN}R)
(III)变长但可穷举的命令(<ESC>[{attr1};...;{attrn}m)
(IV)变长命令(<ESC>[{key};"{string}"p)
对于前三种命令的处理都还算好,对于最后变长命令的处理就比较困难,因为其长度是由{key}来决定的,这里不对这种命令进行讨论。
对于前三种命令最长的长度是10个字节(不带<ESC>,以VT100为例),因为所有的命令及长度都是已知的,所以处理进来比较容易。
对于这些控制字符的处理比较普遍的做法是使用控制语句,如:
if(b =='<ESC>'){
if(nextChar() == '['){
if(nextChar == 'c'){
//do something
}else if(currentChar() == '{ROW}'){
//...
}
}
}
你会发现这种判断语句写起来真的很晕,特别是使用一个指针来拿nextChar,不能匹配的话还得要回退,不容易想清楚,别人也难以读懂。
4、解决办法
使用逐个字符来判断的确不是一个好的方法,这里推荐另一种做法,使用定长字节数据进行判断。这种方法的具体做法如下:
a)把(I)明确的命令使用hash code及对应的处理方法存入map中,其中hash code为该控制命令字节数组的hash code,存储的形式如:map(hashCode, processMethod)。
b)处理(II)定长可变的命令和(III)变长但可穷举的命令,使用类似如下的语句:
byte[] bs = new byte[len];
System.arraycopy(src, startPos, bs, 0, len);
byte b1 = cs[0], b2 = cs[cs.length - 2], be = cs[cs.length - 1];
if (b1 != '[') {continue;}
switch (len) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
//<ESC>[{attr1};...;{attrn}m //<ESC>[{code}0c
if (be == 'm' || (be == 'c' && b2 == '0')) {
//process method
}
break;
case 5:
if (be == 'm' || be == 'r' || be == 'H' || be == 'f' || be == 'R' || (be == 'c' && b2 == '0')) {
//process method
}
break;
case 6:
//...
break;
case 7:
//...
break;
case 8:
//...
break;
case 9:
//...
break;
case 10:
//...
break;
default:
break;
}
5、整个程序的结构
Map<Integer, ProcessMethod> map = new HashMap<Integer, ProcessMethod>();
private List<byte[]> list = Arrays.asList(new byte[1], new byte[2],
new byte[3], new byte[4], new byte[5], new byte[6], new byte[7],
new byte[8], new byte[9], new byte[10]);
private void init() {
map.put(hashCode(new byte[] { '[', 'c' }), new ProcessMethod(){/* process method */});
}
private void process(byte[] bs, int start, int len) {
if (map.isEmpty()) {
init();
}
for (int i = start; i < len; i++) {
byte b = bs[i];
if (b == '<ESC>') {
for (int j = 0; j < list.size() && j + i + 1 < len; j++) {
byte[] cs = list.get(j);
System.arraycopy(bs, i + 1, cs, 0, cs.length);
if (map.contains(hashCode(cs))) {
//map.get(hashCode(cs)).process();
break;
} else {
if (j + 1 < 3) {
continue;
}
byte b1 = cs[0], b2 = cs[cs.length - 2], be = cs[cs.length - 1];
int old = i;
if (b1 != '[') {
continue;
}
switch (j + 1) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
//<ESC>[{attr1};...;{attrn}m //<ESC>[{code}0c
if (be == 'm' || (be == 'c' && b2 == '0')) {
//new ProcessMethod(){/* process method */}.process();
}
break;
case 5:
if (be == 'm' || be == 'r' || be == 'H' || be == 'f' || be == 'R' || (be == 'c' && b2 == '0')) {
//new ProcessMethod(){/* process method */}.process();
}
break;
case 6:
break;
case 7:
break;
case 8:
break;
case 9:
break;
case 10:
break;
default:
break;
}
if (old != i) {
break;
}
}
}
}
}
}
分享到:
相关推荐
它是一个基于字符串的命令语言,基础结构和语法非常简单,易于学习和掌握。 Tcl语言是一个解释性语言,所谓解释性是指不象其他高级语言需要通过编译和联结,它象其他shell语言一样,直接对每条语句顺次解释执行。 ...
Shell是Linux系统下的命令解释器,也是使用Linux系统的主要环境,Shell的功能很多,本章主要从Shell的基本概念、Shell的种类、Shell中的特殊字符、重定向以及Shell程序几个方面来讲解,重点内容是Shell的特殊字符...
Java的产生与流行是当今Internet发展的客观要求,Java是一门各方面性能都很好的编程语言,它的基本特点是简单、面向对象、分布式、解释的、健壮的、安全的、结构中立的、可移植的、性能很优异的、多线程的、动态的,...
* 向串口中写进字符串命令 * @param s 字符串命令 * @throws Exception 异常 */ public void writeln(String s) throws Exception { out.write(s); out.write('\r'); out.flush(); } /** * 读取COM命令...
_Str :将输入流读取的字符串放到_Str 中。 _Delim:遇到这个字符就停止读取,不设置默认为'\n' 本项目是作者初学C++中类相关知识的时候写的一个练习使用类的小项目。 > - 类之间的横向关系和纵向关系是C++中很重要...
RowsTextIO 是一个只读的 Unicode 字符和基于行的接口,用于根据数据库查询的结果流式传输 I/O。 该流可以作为参数提供给的游标方法,以将数据加载到目标表中。 我只在 PostgreSQL 上尝试过这个,但它应该可以与...
扫描系统以找出基于 Rootkit 的恶意软件。 SDelete 安全地覆盖敏感文件,并使用此符合 DoD 的安全删除程序清理先前删除文件所在的可用空间。 ShareEnum 扫描网络上的文件共享并查看其安全设置,以关闭安全漏洞。 ...
Shout down –n now 关机时同步备份内存中的数据 useradd + 用户 创建用户 userdel + user 可以用来删除用户 ...poweroff 关机 reboot 重启 ...3. iptables 基于数据流的防火 4. 内核级别:selinux 5. 服务本身
嵌入式系统开发基础——基于ARM微处理器和Linux操作系统[滕英岩][习题解答] 目录第1章 嵌入式系统基础知识 1.1 嵌入式系统的特点及分类 1.1.1 嵌入式系统的特点 1.1.2 嵌入式系统的分类 1.2 嵌入式系统的软硬件...
4.用awk处理数据流 4.1.工作原理 4.2.补充内容 4.2.1.特殊变量 4.2.2.将外部变量值传递给awk 4.2.3.用getline读取行 4.2.4.用样式对awk的行进行过滤 4.2.5.设置字段定界符 4.2.6.从awk中读取命令输出 4.2.7...
当前系统有4轮麦克纳姆轮小车模型、电机速度环算法PID算法、直流电机驱动L298N模块、串口命令控制台PC机使用串口调试工具向小车发送命令以使小车执行命令相关程序、将不同开发环境的串口结构体等进行封装、实现用户...
19.2.2 格式化流内容元素 530 19.2.3 创建简单的流文档 532 19.2.4 块级别元素 533 19.2.5 内联级别元素 538 19.2.6 通过代码与元素进行交互 543 19.2.7 调整文本 547 19.3 只读流文档包容器 548 19.3.1 缩放...
19.2.2 格式化流内容元素 530 19.2.3 创建简单的流文档 532 19.2.4 块级别元素 533 19.2.5 内联级别元素 538 19.2.6 通过代码与元素进行交互 543 19.2.7 调整文本 547 19.3 只读流文档包容器 548 19.3.1 缩放 549 ...
以及嵌入式Linux的I/O与文件系统的开发、进程控制开发、进程间通信开发、网络应用开发、基于中断的开发、设备驱动程序的开发以及嵌入式图形界面的开发等,并且还安排了丰富的实验内容与课后实践,使读者能够边学边用...
当前,它提供了一组用于在各种替换规则下构建格式化字符串的工具: sprintf C样式格式基于数字的格式基于变量的格式该软件包的主要目的是使产生所有流行样式的格式化字符串变得更加容易。安装您可以使用以下命令从...
与基于sed的基于换行符的程序不同,它允许通过遍历器,缓冲区和命令接口以不同方式读取流。 遍历器决定如何读取数据。 此数据存储在缓冲区中。 这些命令决定如何处理此数据。 通过指定编码,所有数据均以字符形式...
09 基于tcp实现远程执行命令测试结果 10 粘包现象 11 粘包解决方法 第31章 01 上节课复习 02 socketserver实现并发 03 socketserver模块介绍 04 socketserver源码分析tcp版本 05 socketserver源码分析udp版 06 ftp...
String:⽤于处理字符串并验证它们的内容的库,⽤于⽣成、修改和验证字符串 Telnet:⽀持连接到Telnet服务器上打开的连接执⾏命令。 XML:⽤于⽣成、修改和验证XML⽂件的库。 Process:系统中运⾏过程的库。 DateTime:...
2.1.2用户的注册与注销11 2.1.3账户的管理12 2.1.4用户口令的管理12 2.1.5...解释过程57 4.2.2UNIX系统定义的标准流57 4.2.3shell语法管理58 4.2.4标准流重定向与管道线控制58 4.2.5错误流重定向60 4.2.6命令执行控制及...