将字符串解析为单词
代码注释参考github中项目
作者:林良益,卓诗垚
/**
* 分层前:
* 1.读取字符,一个指针走,一个指针停
* 2.读取字符的结果:
* a.没有问题,mark(),mark指针赶上
* b.有问题,reset,指针回退
* 缺点:不能获取有问题的index
*
* 基本元素:字符,开始位置和当前位置
* 组合:开始位置和当前位置的交互
*
*
* 分层后的使用方式
* 1.读取字符
* 2.读取字符结果:
* a.没有问题,mark(mark为本次读取的个数)
* b.有问题,reset重新读取
* 优点:可以获取有问题的index
*
*/
public class LevelReader extends StringReader {
private static final String IGNORE_CHAR = " \r\n\t";//词元间的忽略字符
public static final String NUMBER_CHARS = "01234567890.";//表示数值的字符
private int currentIndex = 0;//当前索引
//用于记录回退的个数
private int markIndex = 0;//被标记后索引
private boolean prefixBlank = false;//与上一个读到的ElementToken之间是否有空格
/**
* Creates a new string reader.
*
* @param s String providing the character stream.
*/
public LevelReader(String s) {
super(s);
}
@Override
public int read() throws IOException {
int c = super.read();
if (c != -1){
currentIndex++;
markIndex++;
}
return c;
}
/**
* 将回退位置清0
* @param readAheadLimit
* @throws IOException
*/
@Override
public void mark(int readAheadLimit) throws IOException {
super.mark(readAheadLimit);
markIndex = 0;
}
/**
* 作用:读错了,重读
* 回退
* 回退到该单词开始的位置
* @throws IOException
*/
@Override
public void reset() throws IOException {
super.reset();
currentIndex = currentIndex - markIndex;
}
@Override
public void close() {
super.close();
}
public void readToken() throws IOException {
//递归字符串中字符
//如果是-1,说明读取结束
//如果是空格等,跳过
//如果不是空格,然后重置,获取处理器
//使用处理器读取
while (true){
//开始读取,说明以前读取的都没有问题,mark为0
mark(0);
int c = read();
if (c == -1){
return ;
}
if (IGNORE_CHAR.indexOf(c) >= 0){
continue;
}
//c不是空格
reset();
Element element = createElementReader();
ExpressionToken expressionToken = changeToToken(element);
//主要用于校验,括号匹配问题
pushParenthesis(element);
//list.add(expressionToken);
}
}
}
public Element createElementReader() throws IOException {
mark(0);
int b = read();
reset();
if (b != -1){
char c = (char) b;
if (NUMBER_CHARS.indexOf(c) >= 0){
Element element = readNumber();
System.out.println(new Gson().toJson(element));
return element;
}
//如果是操作符,操作符的定义+-*/ > >= < <= == != && || ! 等等
//OperatorTypeReader 中包含操作符,Operator中也包含操作符,一个是读取element的时候,一个是转化为RPN的时候(要比较优先级)
// else if (){
//
// }
} else {
System.out.println("流结束了");
}
return null;
}
/**
* 1.数字和点依次添加
* 2.结尾如果是l或者是L,则为long类型
* 3.结尾如果是f或者是F,则为float类型
* 4.结尾如果是d或者是D,则为double类型
* @return
* @throws IOException
*/
public Element readNumber() throws IOException {
int index = currentIndex;
mark(0);
StringBuilder sb = new StringBuilder();
int b = -1;
while ((b = read()) != -1){
char c = (char) b;
if (NUMBER_CHARS.indexOf(c) >= 0){
sb.append(c);
mark(0);
} else {
reset();
return new Element(sb.toString(), index, Element.ElementType.INT);
}
}
return null;
}
/**
* 表达式词元
* @@author 林良益,卓诗垚
* @version 2.0
* Sep 23, 2008
*
*/
public class Element {
public enum ElementType {
//NULL类型
NULL ,
//字符窜
STRING ,
//布尔类
BOOLEAN ,
//整数
INT ,
//长整数
LONG ,
//浮点数
FLOAT ,
//双精度浮点
DOUBLE ,
//日期时间
DATE ,
//变量
VARIABLE ,
//操作符
OPERATOR ,
//函数
FUNCTION ,
//分隔符
SPLITOR
}
private String text;
private ElementType type;//类型
private int index;//元素在表达式中的起始索引号,从0算起
/**
* 构造
* @param text
* @param index
* @param type
*/
public Element(String text, int index, ElementType type) {
this.text = text;
this.index = index;
this.type = type;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public ElementType getType() {
return type;
}
public void setType(ElementType type) {
this.type = type;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
其中element中记录的单词的字符序列,开始索引,单词的类型(整形,long型,字符串,null,函数,分隔符,操作符,变量等等)
public static void main(String[] args) throws IOException {
LevelReader lr = new LevelReader(" 10 > 20 || 30 < 50 && (70 > 80 || 90 > 70)");
lr.readToken();
}