Expression parser for Java string Application

Source: Internet
Author: User

1. Expression Composition
1. Number
2. OPERATOR: +-/* ^ % =
3. parentheses
4. Variables
Ii. Operator priority
From high to low: +-(plus and minus signs), ^, */%, +-, =
Operators with equal priorities are calculated from left to right.
Iii. Key Technical Points
1. Determine the operation priority, from high to low: atomic element expressions, including numbers and variables; parentheses expressions; mona1 expressions; negative numbers; exponential expressions; multiplication, division, modulo expression; addition and subtraction expression; Value assignment expression.
2. Each level of operation is implemented by a method. In a method, the first level of operation is higher than the current level, and then the current level of operation is processed. Therefore, in the main method for calculating the entire expression, you only need to call the implementation method of the lowest level operation.
3. Determine the separators (+,-, *,/, %, ^, =, (,), and) in the expression ,(,),). Use these delimiters to divide the expression into multiple segments. Each segment is called a token, And the Delimiter is also considered a token.
4. Use the int array vars with a length of 26 to store the value of the variable.
5. The character iswhitespace method is used to determine whether the character is a blank character and remove the blank character in the expression.
6. Character's isletter method determines whether the character is a letter and is used to extract the variables in the expression.
7. Character's isdigit method determines whether the character is a number and is used to obtain the number in the expression.

4. Demo instance

 

 

/***//**
* File name expressionparser. Java
*/
Package book. OO. String;

/***//**
* Expression parser
* @ Author Joe
*
*/
Public class expressionparser ...{
// Four tag types
Public static final int none_token = 0; // flag as null or Terminator
Public static final int delimiter_token = 1; // mark as a separator
Public static final int variable_token = 2; // mark it as a variable
Public static final int number_token = 3; // mark as a number

// Four error types
Public static final int syntax_error = 0; // syntax error
Public static final int unbalparens_error = 1; // no ending error in parentheses
Public static final int noexp_error = 2; // The expression is null.
Public static final int divbyzero_error = 3; // The error code returned when the value is 0.

// Four error prompts defined for four error types
Public static final string [] error_messages =... {"syntax error", "unbalanced" +
"Parentheses", "no expression present", "Division by zero "};

// End mark of the expression
Public static final string EOE = ""/0 ";
 
Private string exp; // expression string
Private int expindex; // The Position of the parser's current pointer in the expression
Private string token; // The tag currently processed by the parser
Private int tokentype; // The tag type currently processed by the parser
Private double [] vars = new double [26]; // variable array
/**
*
*/
Public expressionparser (){
}
 
/**
* Parses an expression and returns the value of the expression.
*/
Public double evaluate (string expstr) throws exception {
Double result;
This. Exp = expstr;
This. expindex = 0;

// Obtain the first tag
This. gettoken ();
If (this. Token. Equals (EOE )){
// No expression exception
This. handleerror (noexp_error );
}

Result = This. parseassign (); // process the value assignment statement.
// The Value assignment statement should be the expression Terminator. If not, an exception is returned.
If (! This. Token. Equals (EOE )){
This. handleerror (syntax_error );
}
Return result;
}
 
/**
* Process the value assignment statement
*/
Public double parseassign () throws exception {
Double result; // result
Int varindex; // variable subscript
String oldtoken; // old tag
Int oldtokentype; // type of the old tag

// If the tag type is a variable
If (this. tokentype = variable_token ){
// Save the current tag
Oldtoken = new string (this. Token );
Oldtokentype = This. tokentype;
// Get the index of the variable. This parser only supports the variable of one letter.
// If the user's variable letter length is greater than 1, take the first letter as the variable
Varindex = character. touppercase (this. Token. charat (0)-''a '';

// Obtain the next tag
This. gettoken ();
// If the current mark is not equal to =
If (! This. Token. Equals ("= ")){
This. putback (); // roll back
// It is not a value assignment statement. The mark is restored to the previous mark.
This. Token = new string (oldtoken );
This. tokentype = oldtokentype;
} Else {
// If the current mark is equal to =, assign a value to the variable, for example, a = 3 + 5;
// Calculates the value of the expression after the equal sign, and then assigns the obtained value to the variable.
This. gettoken ();
// Because addition and subtraction have the lowest priority, the addition and subtraction expressions are calculated.
Result = This. parseaddorsub ();
// Assign the expression value to the variable, which exists in the instance variable vars
This. vars [varindex] = result;
Return result;
}
}
// If the current tag type is not a variable or is not a value assignment statement, use addition/subtraction to calculate the value of the expression.
Return this. parseaddorsub ();
}
 
/** Calculate addition/subtraction expressions */
Private double parseaddorsub () throws exception {
Char op; // Operator
Double result; // result
Double partialresult; // the result of the subexpression

Result = This. paresemulordiv (); // use multiplication and division to calculate the value of the current expression.
// If the first letter currently marked is a plus or minus sign, the addition or subtraction operation is continued.
While (OP = This. Token. charat (0) = ''+'' | op = ''-''){
This. gettoken (); // obtain the next tag
// Use multiplication and division to calculate the value of the current subexpression
Partialresult = This. paresemulordiv ();
Switch (OP ){
Case ''-'':
// If it is a subtraction, use the value of the processed subexpression to subtract the value of the current subexpression.
Result = Result-partialresult;
Break;
Case ''+ '':
// For addition, add the value of the current subexpression to the value of the processed subexpression.
Result = Result + partialresult;
Break;
}
}
Return result;
}
/**
* Calculate the multiplication and division expressions, including the modulo operation
*/
Private double paresemulordiv () throws exception {
Char op; // Operator
Double result; // result
Double partialresult; // subexpression result
// Calculate the value of the current subexpression using exponential operations
Result = This. parseexponent ();
// If the first letter of the current tag is multiplication, division, or modulo operation, the multiplication and division operations are continued.
While (OP = This. token. charat (0) = ''*'' | op = ''/'' | op = ''% ''){
This. gettoken (); // remove a tag
// Calculate the value of the current subexpression using exponential operations
Partialresult = This. parseexponent ();
Switch (OP ){
Case ''*'':
// If it is multiplication, multiply the value of the processed subexpression by the value of the current subexpression
Result = Result * partialresult;
Break;
Case ''/'':
// If it is a division, judge whether the value of the current word expression is 0. If it is 0, an exception is thrown
If (partialresult = 0.0 ){
This. handleerror (divbyzero_error );
}
// If the divisor is not 0, division is performed.
Result = Result/partialresult;
Break;
Case ''' % '':
// If it is a modulo operation, you must also determine whether the value of the current subexpression is 0.
If (partialresult = 0.0 ){
This. handleerror (divbyzero_error );
}
Result = Result % partialresult;
Break;
}
}
Return result;
}
 
/**
* Calculate an exponential expression
*/
Private double parseexponent () throws exception {
Double result; // result
Double partialresult; // The value of the subexpression.
Double ex; // base number of the Index
Int t; // The Power of the Index

// Calculate the value (base number) of the current subexpression using the unary operation)
Result = This. parseunaryoperator ();
// If it is marked as "^", it is an exponential operation.
If (this. Token. Equals ("^ ")){
// Obtain the next mark, that is, obtain the power of the index.
This. gettoken ();
Partialresult = This. parseexponent ();
Ex = result;
If (partialresult = 0.0 ){
// If the power of the index is 0, the index value is 1.
Result = 1.0;
} Else {
// Otherwise, the exponential value is the result of multiplying the base number of the exponential power.
For (t = (INT) partialresult-1; t> 0; t --){
Result = Result * Ex;
}
}
}
Return result;
}
 
/**
* Calculate the mona1 operation, +,-, indicating the positive number and negative number.
*/
Private double parseunaryoperator () throws exception {
Double result; // result
String op; // Operator
OP = "";
// If the current tag type is a separator and the delimiter value is + or-
If (this. tokentype = delimiter_token) & this. Token. Equals ("+") | this. Token. Equals ("-")){
OP = This. Token;
This. gettoken ();
}
// Use parentheses to calculate the value of the current subexpression
Result = This. parsebracket ();
If (op. Equals ("-")){
// If the operator is-, it indicates a negative number, and the value of the subexpression is changed to a negative number.
Result =-result;
}
Return result;
}
 
/**
* Parentheses Calculation
*/
Private double parsebracket () throws exception {
Double result; // result
// If it is currently marked as left parenthesis, it indicates a bracket operation.
If (this. Token. Equals ("(")){
This. gettoken (); // remove a tag
Result = This. parseaddorsub (); // calculates the value of a subexpression using addition/subtraction.
// If the current flag is not equal to the right parenthesis, an error occurs when the parentheses do not match.
If (! This. Token. Equals (")")){
This. handleerror (unbalparens_error );
}
This. gettoken (); // otherwise, take the next tag
} Else {
// If it is not a left brace, it indicates that it is not a bracket operation. Then, the subexpression value is calculated using atomic element calculation.
Result = This. parseatomelement ();
}
Return result;
}
 
/**
* Calculate atomic element operations, including variables and numbers
*/
Private double parseatomelement () throws exception {
Double result = 0.0; // result

Switch (this. tokentype ){
Case number_token:
// If the current tag type is Numeric
Try {
// Convert a numeric string to a numeric value
Result = double. parsedouble (this. Token );
} Catch (numberformatexception exc ){
This. handleerror (syntax_error );
}
This. gettoken (); // obtain the next tag
Break;
Case variable_token:
// If the current tag type is a variable, take the value of the Variable
Result = This. findvar (token );
This. gettoken ();
Break;
Default:
This. handleerror (syntax_error );
Break;
}
Return result;
}
 
/**
* Obtain the value of a Variable Based on the variable name. If the variable name length is greater than 1, only the first character of the variable is used.
*/
Private double findvar (string vname) throws exception {
If (! Character. isletter (vname. charat (0 ))){
This. handleerror (syntax_error );
Return 0.0;
}
// Retrieves the value of this variable from the instance variable array vars.
Return vars [character. touppercase (vname. charat (0)-''a'];
}
 
/**
* Roll back to move the current pointer of the parser forward to the current tag location
*/
Private void putback (){
If (this. Token = EOE ){
Return;
}
// The current pointer of the parser moves forward
For (INT I = 0; I <this. Token. Length (); I ++ ){
This. expindex --;
}
}
 
/**
* Handle exceptions
*/
Private void handleerror (INT errortype) throws exception {
// When an exception occurs, obtain the exception prompt based on the error type, encapsulate the prompt information in the exception, and throw
Throw new exception (error_messages [errortype]);
}
 
/**
* Get the next tag
*/
Private void gettoken (){
// Set the Initial Value
This. Token = "";
This. tokentype = none_token;

// Check whether the expression ends. If the parser's current pointer has reached the string length,
// Indicates that the expression has ended and the value of the current tag is EOE.
If (this. expindex = This. Exp. Length ()){
This. Token = EOE;
Return;
}

// Skip the blank characters in the expression
While (this. expindex <this. Exp. Length ()
& Character. iswhitespace (this. Exp. charat (this. expindex ))){
+ + This. expindex;
}

// Check whether the expression ends again
If (this. expindex = This. Exp. Length ()){
This. Token = EOE;
Return;
}

// Get the characters pointed to by the parser's current pointer
Char currentchar = This. Exp. charat (this. expindex );
// If the current character is a separator, it is considered as a separator mark
// Assign values to the current tag and tag type, and move the pointer back
If (isdelim (currentchar )){
This. Token + = currentchar;
This. expindex ++;
This. tokentype = delimiter_token;
} Else if (character. isletter (currentchar )){
// If the current character is a letter, it is considered as a variable tag
// Move the parser pointer back. If you know that a Delimiter is encountered, all the characters in the delimiter are components of the variable.
While (! Isdelim (currentchar )){
This. Token + = currentchar;
This. expindex ++;
If (this. expindex> = This. Exp. Length ()){
Break;
} Else {
Currentchar = This. Exp. charat (this. expindex );
}
}
This. tokentype = variable_token; // you can specify the Flag type as a variable.
} Else if (character. isdigit (currentchar )){
// If the current character is a number, the current tag type is considered as a number
// Move the parser pointer back and know that the character between a separator is a part of the number.
While (! Isdelim (currentchar )){
This. Token + = currentchar;
This. expindex ++;
If (this. expindex> = This. Exp. Length ()){
Break;
} Else {
Currentchar = This. Exp. charat (this. expindex );
}
}
This. tokentype = number_token; // you can specify a number as the tag type.
} Else {
// An unrecognized character is considered as the end of the expression
This. Token = EOE;
Return;
}
}
 
/**
* Determines whether a character is a separator.
* The characters in the expression include:
* Add "+", subtract "-", multiply "*", divide "/", modulo "%", index "^", assign "=", and left bracket" (", right parenthesis")"
*/
Private Boolean isdelim (char c ){
If ("+-*/% ^ = ()". indexof (c )! =-1 ))
Return true;
Return false;
}
/**
* @ Param ARGs
*/
Public static void main (string [] ARGs) throws exception {
Expressionparser test = new expressionparser ();

String exp1 = "A = 5.0 ";
System. Out. println ("exp1 (/" A = 5.0/") =" + test. Evaluate (exp1 ));

String exp2 = "B = 3.0 ";
System. Out. println ("exp2 (/" B = 3.0/") =" + test. Evaluate (exp2 ));

String exp3 = "(a + B) * (a-B )";
System. Out. println ("exp3 (/" (a + B) * (a-B)/") =" + test. Evaluate (exp3 ));

String exp4 = "3 * Five-4/2 ";
System. Out. println ("exp4 (/" 3*5-4/2/") =" + test. Evaluate (exp4 ));

String exp5 = "(4-2) * (A + B)/(a-B ))";
System. out. println ("exp5 (/" (4-2) * (A + B)/(a-B)/") =" + test. evaluate (exp5 ));

String exp6 = "5% 2 ";
System. Out. println ("exp6 (/" 5% 2/") =" + test. Evaluate (exp6 ));

String exp7 = "3 ^ 2*5 + 4 ";
System. Out. println ("exp7 (/" 3 ^ 2*5 + 4/") =" + test. Evaluate (exp7 ));
}
}
 

Output result:

Exp1 ("A = 5.0") = 5.0
Exp2 ("B = 3.0") = 3.0
Exp3 ("(a + B) * (a-B)") = 16.0
Exp4 ("3*5-4/2") = 13.0
Exp5 ("(4-2) * (A + B)/(a-B)") = 8.0
Exp6 ("5% 2") = 1.0
Exp7 ("3 ^ 2*5 + 4") = 49.0

V. instance analysis
Expression Parsing is actually a process of expression decomposition. The expression is divided into several segments based on the delimiter. Then, the value of each segment is calculated, and finally an atomic expression is used.

Article Source: http://www.diybl.com/course/3_program/java/javaxl/20071126/87573.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.