-1

I am working on a program, where I want users to define a simple functions like randomInt(0,10) or randomString(10) instead of static arguments. What is the best way to parse and process such functions ?

I have not found any examples of such problem, the parser does not have to be ultra-efficient, it will not be called often, but mainly I want to focus on good code readability and scalability.

Example of user input:

"This is user randomString(5) and he is randomInt(18,60) years old!"

Expected output(s):

"This is user phiob and he is 45 years old!"

"This is user sdfrt and he is 30 years old!"

Dakado
  • 11
  • 2
  • 6
  • This is too broad. You first have to define your exact requirements. For example: is everything that goes " something()" assumed to be function name? What framework are you using for parsing? Where are the functions coming from, and so on? This is simply a lot of work respectively missing context. – GhostCat Feb 14 '19 at 15:12
  • I guess you are using string to store user input. So it is string you will need to define methods that will call user desired method. After user input `randomInt(18,60)` I would use substring in loop until it reaches `(` and check if that matches any method that is avaiable. Then you will need again substring to get values – bakero98 Feb 14 '19 at 15:17
  • Looks like you want some sort of templating enigne. I suggest Googleing for that ("java templating enigne") before (trying) to write your own. – Bart Kiers Feb 14 '19 at 15:48

2 Answers2

0

One option is to use Spring SPEL. But it forces you to change the expression a little and use Spring library:

The expression can look like this:

'This is user ' + randomString(5) + ' and he is ' + randomInt(18,60) + ' years old!'

or this:

This is user #{randomString(5)} and he is #{randomInt(18,60)} years old!

or you can implement your own by having a custom TemplateParserContext.

And here is the code:

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class SomeTest {

        @Test
        public void test() {
            ExpressionParser parser = new SpelExpressionParser();

            Expression exp = parser.parseExpression(
                "This is user #{randomString(5)} and he is #{randomInt(18,60)} years old!", 
                new TemplateParserContext() );

            //alternative
            //Expression exp = parser.parseExpression(
            //        "'This is user ' + randomString(5) + ' and he is ' + randomInt(18,60) + ' years old!'");
            //    String message = (String) exp.getValue( new StandardEvaluationContext(this) );


            String message = (String) exp.getValue( new StandardEvaluationContext(this) );
        }

        public String randomString(int i) {
            return "rs-" + i;
        }

        public String randomInt(int i, int j) {
            return "ri-" + i + ":" + "j";
        }

    }

Whatever object you pass to StandardEvaluationContext should have those methods. I put them in the same class that also runs the expression.

tsolakp
  • 5,858
  • 1
  • 22
  • 28
-1

You could use something such as the following: Warning, I haven't tested it. Just something to get started with

public String parseInput(String input){
    String[] inputArray = input.split(" ");
    String output = "";
    for(String in : inputArray){ //run through each word of the user input
        if(in.contains("randomString(")){ //if the user is calling randomString
            String params = in.replace("randomString(", ""); //strip away function to get to params
            params = in.replace("(", ""); //strip away function to get to params
            String[] paramsArray = params.split(",");  //these are string integers, and could be converted
            //send off these split apart parameters to your randomString method
            String out = randomString(paramsArray); //method parses string integers, outputs string
            output += out + " ";
        }else if(in.contains("randomInt(")){ //if the user is calling randomInt
            String params = in.replace("randomInt(", ""); //strip away function to get to params
            params = in.replace("(", ""); //strip away function to get to params
            String[] paramsArray = params.split(","); //these are string integers, and could be converted
            //send off these split apart parameters to your randomInt method
            String out = randomInt(paramsArray); //method parses string integers, outputs string
            output += out + " ";
        }else{ //if the user is just entering text
            output += in + " "; //concat the output with what the user wrote plus a space
        }

    }
    return output;
}
  • Sure, I know how to do it "the messy way" but imagine doing this for 20 + users functions, it will be like 1000+ of lines of unreadable code. I am asking for a cleaner solution. – Dakado Feb 14 '19 at 15:30
  • I would look into the java Stream methods if you're using a new enough JDK. You could split the user input into words, stream that array, and check each word against a list of trigger functions. The java Stream methodology would definitely give you cleaner code. – Brandon Beiler Feb 14 '19 at 15:34