This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Convert String to code
I need to evaluate a string containing valid Java code
eg. I should be able to get 6 from String code="Math.abs(2*3);";
This sounds like quite an interesting idea, can I ask what the purpose of your application will be?
The best bet is to build up a dictionary of known patterns you will support.
My first idea is that you should create an ArrayList of accepted patterns. So for example:
ArrayList<String> acceptedPatterns = new ArrayList<String>();
acceptedPatterns.add("math.abs");
acceptedPatterns.add("math.acos");
etc.
Then you can evaluate this list when you get hold of the string.
String foundPattern = null;
String myStringFromInput = editText.getText();
for (String pattern : acceptedPatterns){
if (myStringFromInput.contains(pattern){
// we have recognised a java method, flag this up
foundPattern = pattern;
break;
}
}
At this point you would have "Math.abs" in your foundPattern variable.
You could then use your knowledge of how this method works to compute it. I can't think of a super efficient way, but a basic way that would at least get you going would be something like a big if/else statement:
int result = 0;
if (foundPattern.contains("Math.abs"){
result = computeMathAbs(myStringFromInput);
}else if (foundPattern.contains("Math.acos"){
// etc
}
And then in your computeMathAbs method you would do something like this:
private int computeMathAbs(String input){
int indexOfBracket = input.indexOf("(");
int indexOfCloseBracket = input.indexOf(")");
String value = input.subString(indexOfBracket,indexOfCloseBracket);
int valueInt = computeFromString(value);
int result = Math.abs(valueInt);
return result;
}
You could then display the result passed back.
The computeFromString() method will do a similar thing, looking for the * symbol or other symbols and turning this into a multiplication like the abs example.
Obviously this is a basic example, so you would only be able to compute one java method at a time, the complexity for more than one method at a time would be quite difficult to program I think.
You would also need to put quite a bit of error handling in, and recognise that the user might not enter perfect java. Can of worms.
You can use Groovy http://groovy.codehaus.org/api/groovy/util/Eval.html
import groovy.util.Eval;
...
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("a", 2);
params.put("b", 3);
Integer res = (Integer) Eval.me("param", params, "Math.abs(param.a * param.b)");
System.out.println("res with params = " + res);
System.out.println("res without params = " + Eval.me("Math.abs(2*3)"));
Related
This question already has an answer here:
How to use single Servlet with different URL pattern?
(1 answer)
Closed 3 years ago.
I am currently using /Main as the default url-pattern.
It is possible to replace this with /Main2 or another word, but I would like to add one directory such as /Project/Main.
/Project path is not really present, but just want /Main and /Project/Main to work the same way.
In other words, it is hoped that the described routes will invoke one servlet. Is there a way?
ex) 172.0.0.1/Project/Main = 172.0.0.1/Main
=> result : Main_servlet
To my knowledge, you can only pass to the main knowledge in String format. This is because things passed to the main method come from System.in, either through random user input or things like piping, whereby you pass Strings from one Java program to another.
That being said, what you could do is that you create a method in your object class to parse a String form of that object to recreate the original version of that object.
For example:
public class myRectangle
{
private int length;
private int width;
public myRectangle(int inLength, int inWidth)
{
this.length = inLength;
this.width = inWidth;
}
// the rest of your class
public String toString()
{
return "[" + length + ", " + width + "]";
}
public static Rectangle parseString(String input)
{
int firstBracketIndex;
int commaIndex;
int lastBracketIndex;
firstBracketIndex = 0;
commaIndex = input.indexOf(",");
lastBracketIndex = input.length() - 1;
String aWidth = input.substring(firstBracketIndex, (commaIndex - 1));
String aLength = input.substring((commaIndex + 2), lastBracketIndex);
return new Rectangle(Integer.parseInt(aWidth), Integer.parseInt(aLength));
}
}
Something like this could solve your problem. (There may be some off by one errors in my code and I wrote it out really long so it would be clear, but you get the idea!)
The point is, that you create a parsing method that is the inverse of your toString method, so that you can take copies of your class off the command line.
I have this pipeline where i stream data from Python and connect to the stream in a Java applicaton. The data records are matrices of complex numbers. Now I've learned that json.dumps() can't deal with pythons complex type.
For the moment I've converted the complex values to a string, put it in a dictionary like this:
for entry in range(len(data_array)):
data_as_string = [str(i) for i in data_array[entry]["DATA"].tolist()]
send({'data': data_array[entry]["DATA"],
'coords': data_array[entry]["UVW"].tolist()})
and send it to he pipeline. But this requires extensive and expensive custom deserialization in Java, which increases the running time of the pipeline by a lot.
Currently I'm doing the deserialization like this:
JSONObject = new JSONOBJECT(string);
try {
data= jsonObject.getString("data");
uvw= jsonObject.getString("uvw");
} catch (JSONException ex) {
ex.printStackTrace();
}
And then I'm doing a lot of data.replace(string1, string2) to remove some of the signs added by the serialization and then looping through the matrix to convert every number into a Java Complex type.
My Java deserialization code looks the following:
data = data.replace("(","");
data = data.replace(")","");
data = data.replace("\"","");
data = data.replace("],[","¦");
data = data.replace("[","");
data = data.replace("]","");
uvw = uvw.replace("[","");
uvw = uvw.replace("]","");
String[] frequencyArrays = data.split("¦");
Complex[][] tempData = new Complex[48][4];
for(int i=0;i< frequencyArrays.length;i++){
String[] complexNumbersOfAFrequency = frequencyArrays[i].split(", ");
for(int j =0;j<complexNumbersOfAFrequency.length;j++){
boolean realPartNegative = false;
Complex c;
if(complexNumbersOfAFrequency[j].startsWith("-")){
realPartNegative = true;
//Get ridd of the first - sign to be able to split the real & imaginary parts
complexNumbersOfAFrequency[j] =complexNumbersOfAFrequency[j].replaceFirst("-","");
}
if(complexNumbersOfAFrequency[j].contains("+")){
String[] realAndImaginary = complexNumbersOfAFrequency[j].split("\\+");
try {
double real = Double.parseDouble(realAndImaginary[0]);
double imag = Double.parseDouble(realAndImaginary[1].replace("j",""));
if(realPartNegative){
c = new Complex(-real,imag);
} else {
c = new Complex(real,imag);
}
}catch(IndexOutOfBoundsException e) {
//System.out.println("Wrongly formatted number, setting it to 0");
c = new Complex(0,0);
}
catch (NumberFormatException e){
System.out.println("Wrongly formatted number, setting it to 0");
c = new Complex(0,0);
}
} else {
String[] realAndImaginary = complexNumbersOfAFrequency[j].split("-");
try {
double real = Double.parseDouble(realAndImaginary[0]);
double imag = Double.parseDouble(realAndImaginary[1].replace("j", "").replace("e", ""));
if (realPartNegative) {
c = new Complex(-real, -imag);
} else {
c = new Complex(real, -imag);
}
}
catch(IndexOutOfBoundsException e){
System.out.println("Not correctly formatted: ");
for(int temp = 0;temp<realAndImaginary.length;temp++){
System.out.println(realAndImaginary[temp]);
}
System.out.println("Setting it to (0,0)");
c = new Complex(0,0);
}
catch (NumberFormatException e){
c = new Complex(0,0);
}
}
tempData[i][j] = c;
}
}
Now my question would be if there is a way to either
1)Deserialize the Dictionary in Java without expensive String manipulations and looping through the matrices for each record or
2)Do a better Job in serializing the data in python so that it can be done better in java
Any hints are appreciated.
Edit: JSON looks the following
{"data": ["[(1 + 2j), (3 + 4j), ...]","[(5 + 6j), ...]", ..."],
"coords": [1,2,3]}
Edit: For the coordinates I can do the deserialization in Java pretty easily:
uvw = uvw.replace("[","");
uvw = uvw.replace("]","");
String[] coords = uvw.split(",");
And then cast the Strings in coords with Double.parseDouble(), howver for the data string this is way more complicated because the string is full of characters that need to be removed in order to get the actual numbers and to put them in the right place in the Complex[][] I want to cast it to
You are over-using JsonObject.getString, by using it to retrieve non-string data.
Let’s start with the coords property, since it’s a simpler case. [1,2,3] is not a string. It’s an array of numbers. Therefore, you should retrieve it as an array:
JsonArray coords = jsonObject.getJsonArray("coords");
int count = coords.size();
double[] uvw = new double[count];
for (int i = 0; i < count; i++) {
uvw[i] = coords.getJsonNumber(i).doubleValue();
}
The other property, data, is also an array, but with string elements:
JsonArray data = jsonObject.getJsonArray("data");
int count = data.size();
for (int i = 0; i < count; i++) {
String complexValuesStr = data.getString(i);
// ...
}
As for parsing out the complex numbers, I wouldn’t make all those String.replace calls. Instead, you can look for each complex value with a regular expression matcher:
Pattern complexNumberPattern = Pattern.compile(
"\\(\\s*" + // opening parenthesis
"(-?[0-9.]+)" + // group 1: match real part
"\\s*([-+])\\s*" + // group 2: match sign
"([0-9.]+)j" + // group 3: match imaginary part
"\\s*\\)"); // closing parenthesis
Matcher matcher = complexNumberPattern.matcher("");
JsonArray data = jsonObject.getJsonArray("data");
int count = data.size();
List<List<Complex>> allFrequencyValues = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
String complexValuesStr = data.getString(i);
List<Complex> singleFrequencyValues = new ArrayList<>();
matcher.reset(complexValuesStr);
while (matcher.find()) {
double real = Double.parseDouble(matcher.group(1));
boolean positive = matcher.group(2).equals("+");
double imaginary = Double.parseDouble(matcher.group(3));
Complex value = new Complex(real, positive ? imaginary : -imaginary);
singleFrequencyValues.add(value);
}
allFrequencyValues.add(singleFrequencyValues);
}
You should not catch IndexOutOfBoundsException or NumberFormatException. Those indicate the input was invalid. You should not treat invalid input like it’s zero; it means the sender made an error, and you should make sure to let them know it. An exception is a good way to do that.
I have made the assumption that both terms are always present in each complex expression. For instance, 2i would appear as 0 + 2j, not just 2j. And a real number like 5 would appear as 5 + 0j. If that is not a safe assumption, the parsing gets more complicated.
Since you are concerned with performance, I would try the above; if the use of a regular expression makes the program too slow, you can always look for the parentheses and terms yourself, by stepping through the string. It will be more work but may provide a speed increase.
If I understand you correctly, your matrix would consist of arrays of complex numbers which in turn would contain a real number and an imaginary one.
If so, your data could look like this:
[[{'r':1,'j':2},{'r':3,'j':4}, ...],[{'r':5,'j':6}, ...]]
That means that you have a JSON array which contains arrays that contain objects. Those objects have 2 properties: r defining the value of the real number and j the value of the imaginary one.
Parsing that in Java should be straight forward, i.e. with some mapper like Jackson or Gson you'd just parse it into something like ComplexNumber[][] where ComplexNumber could look like this (simplified):
public class ComplexNumber {
public double r;
public double j;
}
Of course there may be already existing classes for complex numbers so you might want to use those. Additionally you might have to deserialize that manually (either because the target classes don't make it easy for the mappers or you can't/don't want to use a mapper) but in that case it would be just a matter of iterating over the JSONArray elements and extracting r and j from the JSONObjects.
I'm trying to solve a calculation problem in Java.
Suppose my data looks as follows:
466,2.0762
468,2.0799
470,2.083
472,2.0863
474,2.09
476,2.0939
478,2.098
It's a list of ordered pairs, in the form of [int],[double]. Each line in my file contains one pair. The file can contain seven to seven thousand of those lines, all of them formatted as plain text.
Each [int] must be subtracted from the [int] one line above and the result written onto another file. The same calculation must be done for every [double]. For example, in the data reported above, the calculation should be:
478-476 -> result to file
476-474 -> result to file
(...)
2.098-2.0939 -> result to file
2.0939-2.09 -> result to file
and so on.
I beg your pardon if this question will look trivial for the vast majority of you, but after weeks trying to solve it, I got nowhere. I also had troubles finding something even remotely similar on this board!
Any help will be appreciated.
Thanks!
Read the file
Build the result
Write to a file
For the 1. task there are already several good answers here, for example try this one: Reading a plain text file in Java.
You see, we are able to read a file line per line. You may build a List<String> by that which contains the lines of your file.
To the 2. task. Let's iterate through all lines and build the result, again a List<String>.
List<String> inputLines = ...
List<String> outputLines = new LinkedList<String>();
int lastInt = 0;
int lastDouble = 0;
boolean firstValue = true;
for (String line : inputLines) {
// Split by ",", then values[0] is the integer and values[1] the double
String[] values = line.split(",");
int currentInt = Integer.parseInt(values[0]);
double currentDouble = Double.parseDouble(values[1]);
if (firstValue) {
// Nothing to compare to on the first run
firstValue = false;
} else {
// Compare to last values and build the result
int diffInt = lastInt - currentInt;
double diffDouble = lastDouble - currentDouble;
String outputLine = diffInt + "," + diffDouble;
outputLines.add(outputLine);
}
// Current values become last values
lastInt = currentInt;
lastDouble = currentDouble;
}
For the 3. task there are again good solutions on SO. You need to iterate through outputLines and save each line in a file: How to create a file and write to a file in Java?
I am currently trying to make a naming convention. The idea behind this is parsing.
Lets say I obtain an xml doc. Everything can be used once, but these 2 in the code below can be submitted several times within the xml document. It could be 1, or simply 100.
This states that ItemNumber and ReceiptType will be grabbed for the first element.
ItemNumber1 = eElement.getElementsByTagName("ItemNumber").item(0).getTextContent();
ReceiptType1 = eElement.getElementsByTagName("ReceiptType").item(0).getTextContent();
This one states that it will grab the second submission if they were in their twice.
ItemNumber2 = eElement.getElementsByTagName("ItemNumber").item(1).getTextContent();
ReceiptType2 = eElement.getElementsByTagName("ReceiptType").item(1).getTextContent();
ItemNumber and ReceiptType must both be submitted together. So if there is 30 ItemNumbers, there must be 30 Receipt Types.
However now I would like to set this in an IF statement to create variables.
I was thinking something along the lines of:
int cnt = 2;
if (eElement.getElementsByTagName("ItemNumber").item(cnt).getTextContent();)
**MAKE VARIABLE**
Then make a loop which adds one to count to see if their is a third or 4th. Now here comes the tricky part..I need them set to a generated variable. Example if ItemNumber 2 existed, it would set it to
String ItemNumber2 = eElement.getElementsByTagName("ItemNumber").item(cnt).getTextContent();
I do not wish to make pre-made variable names as I don't want to code a possible 1000 variables if that 1000 were to happen.
KUDOS for anyone who can help or give tips on just small parts of this as in the naming convention etc. Thanks!
You don't know beforehand how many ItemNumbers and ReceiptTypes you'll get ? Maybe consider using two Lists (java.util.List). Here is an example.
boolean finished = ... ; // true if there is no more item to process
List<String> listItemNumbers = new ArrayList<>();
List<String> listReceiptTypes = new ArrayList<>();
int cnt = 0;
while(!finished) {
String itemNumber = eElement.getElementsByTagName("ItemNumber").item(cnt).getTextContent();
String receiptType = eElement.getElementsByTagName("ReceiptType").item(cnt).getTextContent();
listItemNumbers.add(itemNumber);
listReceiptTypes.add(receiptType);
++cnt;
// update 'finished' (to test if there are remaining itemNumbers to process)
}
// use them :
int indexYouNeed = 32; // for example
String itemNumber = listItemNumbers.get(indexYouNeed); // index start from 0
String receiptType = listReceiptTypes.get(indexYouNeed);
Here is a small Java Code Snippet.
ConfigData[] cd = new ConfigData[1];
cd[0] = new ConfigData();
byte[] tmpbyte ={1,(byte)0x01};
cd[0].settmpdata(tmpbyte);
"ConfigData" is my custom Type (int, Byte Array).
In my last thread i found the tip how to Build / work with a "ByteArray" in php.
But this seems to be a question of the structure of those objects / array.
So..
How can i depict that in PHP.
I hope that this can make some guidelines for you, in the terms of what you can do in PHP, and in a relation to your code snippet (the code is tested):
<?php
// define class
class ConfigData
{
var $intVal;
var $tmpData;
}
$cData = new ConfigData(); // new ConfigData instance
$array[0] = $cData; // put it in a single element array
$array[0]->intVal = 5; // assign an integer to intVal
$array[0]->tmpData = array(1, 1, 2); // assign an array of whatever to tmpData
foreach($array[0]->tmpData as $val) // iterate through assigned array
echo $val." "; // print array item (and append " " )
?>
Now, you might also want to check how byte manipulation in PHP is achieved. I suggest you to do a little Google search, and maybe check the official manual. You question was not specific enough, so I can't say more.