Reputation: 1785
What would be the most efficient (low CPU time) way of achieving the following in Java ?
Let us say we have a list of strings as follows :
1.T.methodA(p1).methodB(p2,p3).methodC(p4)
2.T.methodX.methodY(p5,p6).methodZ()
3 ...
At runtime we get strings as follows that may match one of the strings in our list :
a.T.methodA(p1Value).methodB(p2Value,p3Value).methodC(p4Value) // Matches 1
b.T.methodM().methodL(p10) // No Match
c.T.methodX.methodY(p5Value,p6Value).methodZ() // Matches 2
I would like to match (a) to (1) and extract the values of p1,p2,p3 and p4 where:
p1Value = p1, p2Value = p2, p3Value = p3 and so on.
Similarly for the other matches like c to 2 for example.
Upvotes: 1
Views: 78
Reputation: 3003
The first method I have in mind is of course a regular expression.
But that could be complicated to update in the future or to handle hedge cases.
Instead you can try using the Nashorn engine, that allow you to exec javascript code in a jvm.
So you just need to create a special javascript object that handle all your methods:
private static final String jsLib = "var T = {" +
"results: new java.util.HashMap()," +
"methodA: function (p1) {" +
" this.results.put('p1', p1);" +
" return this;" +
"}," +
"methodB: function (p2, p3) {" +
" this.results.put('p2', p2);" +
" this.results.put('p3', p3);" +
" return this;" +
"}," +
"methodC: function (p4) {" +
" this.results.put('p4', p4);" +
" return this.results;" +
"}}";
This is a string for semplicity, than handle your first case. You can write the code in a js file and load that one easely.
You create a special attribute in your javascript object, that is a Java HashMap, so you get that as the result of the evaluation, with all the values by name.
So you just eval the input:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
final String inputSctipt = "T.methodA('p1Value').methodB('p2Value','p3Value').methodC('p4Value')";
try {
engine.eval(jsLib);
Map<String, Object> result = (Map<String, Object>)engine.eval(inputSctipt);
System.out.println("Script result:\n" + result.get("p1"));
} catch (ScriptException e) {
e.printStackTrace();
}
And you got:
Script result: p1Value
In the same way you can get all the other values.
You need to ignore the script errors, are they should be path not implemented.
Just remember to reset the script context before each evaluation, in order to avoid to mix with previous values.
The advantage of this solution compared to regular expressions is that is easy to understand, easy to update when needed.
The only disadvantage I can see is the knowledge of Javascript, of course, and the performances.
You didn't mention the performances as an issue, so you can try this way if is fine for your need.
If you need a better peroformance than you should look on regular expressions.
UPDATE
To have a more complete answer, here is the same example with regular expressions:
Pattern p = Pattern.compile("^T\\.methodA\\(['\"]?(.+?)['\"]?\\)\\.methodB\\(['\"]?([^,]+?)['\"]?,['\"]?(.+?)['\"]?\\)\\.methodC\\(['\"]?(.+?)['\"]?\\)$");
Matcher m = p.matcher(inputSctipt);
if (m.find()) {
System.out.println("With regexp:\n" + m.group(1));
}
Please be aware that this expression didn't handle hedge cases, and you're going to need a reg exp for each string you want to parse and grab the attribute values.
Upvotes: 2