字符串表达式解析提示?

jdc*_*589 6 java lambda parsing list-comprehension

我在今年的假日季节感到无聊,并随机决定为Java编写一个简单的列表理解/过滤库(我知道那里有一些很棒的,我只是想把它自己写得很糟糕).

对于此列表:

LinkedList<Person> list = new LinkedList<Person>();
            list.add(new Person("Jack", 20));
            list.add(new Person("Liz", 58));
            list.add(new Person("Bob", 33));
Run Code Online (Sandbox Code Playgroud)

语法是:

Iterable<Person> filtered = Query.from(list).where(
    Condition.ensure("Age", Op.GreaterEqual, 21)
    .and(Condition.ensure("Age", Op.LessEqual, 50));
Run Code Online (Sandbox Code Playgroud)

我知道它的丑陋,但如果我使用静态导入并使用更短的方法名称,它变得非常简洁.

以下语法是最终目标:

Iterable<Person> list2 = Query.from(list).where("x=> x.Age >= 21 & x.Age <= 50");
Run Code Online (Sandbox Code Playgroud)

显然,表达式解析不是我最强的区域,我在解析嵌套/多个条件时遇到了麻烦.有人知道我可能会发现有用的一些资源/文献吗?

我现在只有从String lambda语法中成功解析出单个条件表达式:"x=> x.Name == Jack".我的底层Expression结构非常可靠,可以轻松处理任何数量的嵌套,问题只是从字符串解析表达式.

谢谢

只是为了解决问题,这里有一点了解幕后的表达结构是如何工作的(显然我可以在下面的例子中指定'op.GreaterEqual'等...但我想证明它是如何灵活的到任何数量的嵌套):

Condition minAge1 = Condition.ensure("Age", Op.Equal, 20);
Condition minAge2 = Condition.ensure("Age", Op.Greater, 20);
Expression minAge = new Expression(minAge1, Express.Or, minAge2);
Expression maxAge = Condition.ensure("Age", Op.Equal, 50).or(Condition.ensure("Age", Op.Less, 50));
Expression ageExpression = new Expression(minAge, Express.And, maxAge);

Condition randomException = Condition.ensure("Name", Op.Equal, "Liz");
Expression expressionFinal = new Expression(ageExpression, Express.Or, randomException);
Run Code Online (Sandbox Code Playgroud)

cle*_*tus 5

基本上你想要的是表达式的递归下降解析器.这是编译器理论中的一个主题,所以任何关于编译器的书都将涵盖这个主题.在正式的语法术语中,它看起来像这样:

condition  : orAtom ('||' orAtom)+ ;
orAtom     : atom ('&&' atom)+ ;
atom       : '(' condition ')'
           | expression ;
expression : value OPER value ;
value      : VARIABLE | LITERAL '
VARIABLE   : (LETTER | '_') (LETTER | DIGIT | '_')* ;
LITERAL    : NUMBER
           | STRING ;
NUMBER     : '-'? DIGIT+ ('.' DIGIT+)? ;
STRING     : '"' . CHAR* . '"' '
CHAR       : ('\\' | '\"' | .) + ;
LETTER     : 'a'..'z' | 'A'..'Z' ;
DIGIT      : '0'..'9' ;
OPER       : '>' | '>=' | '<' | '<=' | '=' | '!=' ;
Run Code Online (Sandbox Code Playgroud)

上面的语法(大部分)是ANTLR形式,就像我最熟悉的那样.

在处理解析时,解析布尔或算术表达式是一个经典的介绍性主题,因此您应该能够找到大量有关它的文献.如果你想追求ANTLR(因为你正在使用Java),我强烈建议你阅读The Definitive ANTLR Reference:Building Domain-Specific Languages.

如果所有这些看起来有点过分而且有点太多可以接受,那么你可能是对的.入门是一个艰难的话题.

你有一个替代方案是不创建一个任意的字符串表达式,而是使用一个流畅的接口(就像你正在做的那样):

List results = from(source)
  .where(var("x").greaterThan(25), var("x").lessThan(50))
  .select("field1", "field2");
Run Code Online (Sandbox Code Playgroud)

因为这是在代码中声明表达式树并且应该更容易实现.