1

Since Java doesn't have an eval() module, and I want to write my own regex to parse strings into a double[][], e.g.

[in]:

`{{1.23,8.4},{92.12,-0.57212}}`
`{{1.23,-8.4}, {-92.12,-0.57212}}`

[code]:

 double[][] xArr;
 // Somehow read the string into something like this:
 xArr = new double[][] {{1.23,8.4},{92.12,-0.57212}};
 System.out.println(xArr[0][0] + " " + xArr[0][1]);

[out]:

 1.23 -8.4

Currently, I'm doing it as such:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import java.util.ArrayList;
import java.util.List;

public class HelloWorld {

    public static void main(String[] args) {
        String s = "{{1.23,8.4}, {92.12,-0.57212}}";

        Pattern regex = Pattern.compile("((-)?\\d+(?:\\.\\d+)?)");
        Matcher matcher = regex.matcher(s);
        List<double[]> locations = new ArrayList<double[]>();
        int i = 0;
        while(matcher.find()){
            double d1 = Double.parseDouble(matcher.group(1));
            matcher.find();
            double d2 = Double.parseDouble(matcher.group(1));
            locations.add(new double[] {d1, d2});
            i++;        
        }; 


    }

}

Is there a better way to do this? I.e.:

  • Now, the code is sort of cheating by know that my inner size of the double[][] is 2 and during iteration through match.find(). It does 2 passes to skip to the next pair, is there a way to change the regex such that it extracts 2 groups at a time?

  • Currently it's reading into the d1 and d2 variable before create a new double[] to add to the List, is there a way to do it directly without creating d1 and d2?

Community
  • 1
  • 1
alvas
  • 115,346
  • 109
  • 446
  • 738
  • If you don't care about performance you could use a Javascript engine in Java, like here: http://stackoverflow.com/a/2605051/2947592 – wvdz Jul 05 '16 at 08:54
  • @wvdz, how do you convert the resulting `Object` to `double[][]`? – alvas Jul 05 '16 at 09:01
  • What about using the `matcher.groupCount()` to find the size of the double array ? – Viswanath Lekshmanan Jul 05 '16 at 09:10
  • You can cast it to `NativeArray` and then just manually convert it to a `double[][]`. I don't think it's the best approach, but might be easier then fixing your regex, if you just need a quick fix. I think using regex is nicer though. – wvdz Jul 05 '16 at 09:11

3 Answers3

6

Use jackson but you will have to replace the braces with boxes/parenthesis.

With this you don't need to specify the dimensions of the expected array

public static void main(String[] args) throws IOException {
    String jsonString = "{{1.23,8.4}, {92.12,-0.57212}}";
    jsonString = jsonString.replace("{", "[").replace("}", "]");
    Double[][] doubles = new ObjectMapper().readValue(jsonString, Double[][].class);
    System.out.println(Arrays.deepToString(doubles));
}
Olayinka
  • 2,813
  • 2
  • 25
  • 43
4

Here is a Java 8 solution I came up with:

String test = "{{1.23,8.4},{92.12,-0.57212}}";

double[][] vals = Arrays.stream(test.replaceAll(" ", "").split("},\\{"))
                        .map(str -> str.replaceAll("[{}]", "").split(","))
                        .map(Arrays::stream)
                        .map(stream -> stream.mapToDouble(Double::parseDouble)
                                             .toArray())
                        .toArray(double[][]::new);

System.out.println(Arrays.deepToString(vals));

Output:

[[1.23, 8.4], [92.12, -0.57212]]

Or if you want a Double[][]:

Double[][] vals = Arrays.stream(test.replaceAll(" ", "").split("},\\{"))
                        .map(str -> str.replaceAll("[{}]", "").split(","))
                        .map(Arrays::stream)
                        .map(stream -> stream.map(Double::parseDouble)
                                             .toArray(Double[]::new))
                        .toArray(Double[][]::new);

Explanation:

First any whitespace is removed and the string is split on the pattern },\\{ which will result in a String[] where each String is one of the double[]s with some excess curly braces:

["{{1.23,8.4", "92.12,-0.57212}}"]

Then, for each String the curly braces are removed, and the String is split again. So each String becomes a String[] where each value is the String representation of a "double":

[["1.23", "8.4"],["92.12", "-0.57212"]]

These strings are then parsed into doubles, and everything is collected into a double[] and then a double[][]:

[[1.23, 8.4], [92.12, -0.57212]]
explv
  • 2,709
  • 10
  • 17
  • I'm getting `error: incompatible types: String cannot be converted to double[][]` on `Arrays.deepToString(vals)` – alvas Jul 05 '16 at 14:57
  • @alvas Is your code exactly the same as my post? Because I have tested it and it works. – explv Jul 05 '16 at 15:06
  • I have `Double[][] vals;` before doing the conversion. It's a variable that's declare way up in my code. – alvas Jul 05 '16 at 15:10
  • Ah, i got it, i had `double[][] locationArray = Arrays.deepToString(vals);` How do i get from `Double[][]` to `double[][]`? – alvas Jul 05 '16 at 15:13
  • Thanks!! Ah, I could change the type at the last conversion streaming =) – alvas Jul 05 '16 at 15:16
  • Could you also leave the answer for the type resulting in Double[][] too? I think i'll help others in the future =) – alvas Jul 05 '16 at 15:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/116491/discussion-between-explv-and-alvas). – explv Jul 05 '16 at 15:35
0
  1. Question:

    is there a way to change the regex such that it extracts 2 groups at a time

Yes. You could extract a whole line with one pattern, by using your existing one. You have to add the paranthesis and the komma and a the + operator (for multiple values). When you have a single line, you can extract the values with your current pattern, until there are no more found (with a while loop).

  1. Question:

    is there a way to do it directly without creating d1 and d2?

I don't know exactly what you mean. Where is the problem with creating them? With the suggested way on question 1, you could store every value directly in a list as well and hen create a array from it.

I like the solution of Olayinka, too if your format dont change.

Felix S.
  • 126
  • 4