2
\$\begingroup\$

The problem is not very complicated (I mean it is easy to solve it), but the question is how to make it in the easiest way (Java)

Input String:

String inputString = "[value=20][param=304.2][indicator=1500]";

Expected output: array of doubles : [20.0][304.2][1500.0]

Sample solution:

String[] chunks = inputString.split("=");
String valueStr = chunks[1].substring(0, chunks[1].indexOf(']'));
String paramStr = chunks[2].substring(0, chunks[2].indexOf(']'));
String indicatorStr = chunks[3].substring(0, chunks[3].indexOf(']'));
// parsing by Double.parseDouble forming an array and returning it as a result.

What other (smarter) way would you propose using Java?

\$\endgroup\$
6
\$\begingroup\$

Don't know if using regex is overkill, but it does open up for a fairly concise and (in my opinion) readable solution.

public class ArgumentParser {
    public static final Pattern KEY_VALUE_PATTERN = Pattern.compile("\\[([a-zA-Z]+)=(-?\\d+\\.?\\d*)\\]");

    public Map<String, Double> parse(String str) {
        Map<String, Double> values = new HashMap<>();

        Matcher matcher = KEY_VALUE_PATTERN.matcher(str);
        while (matcher.find()) {
            String key = matcher.group(1);
            Double value = Double.parseDouble(matcher.group(2));
            values.put(key, value);
        }

        return values;
    }
}

Edit: The question did ask for an array of doubles to be returned, but that should be trivial to obtain once the parsing is done. Alternatively the parse-method could be modified to only extract the values.

\$\endgroup\$
  • \$\begingroup\$ The regular expression should probably allow an optional negative sign. \$\endgroup\$ – 200_success Dec 11 '13 at 22:40
  • \$\begingroup\$ Good point. I've updated the answer to allow for this. \$\endgroup\$ – Bjoern H Dec 12 '13 at 13:15
4
\$\begingroup\$

Aside from the easiest code, you might want to consider correct and robust code.

Assume following input: [ param=40.2] [foobar =20] junk [=1500]. Your code will actually parse this, even though that is likely to be wrong. You have to test if the input actually conforms to a certain format. During parsing, you throw away the information from the labels like param, and rather rely on the order. If you don't check for validity, and the format changes unexpectedly, you'll have hard to trace bugs.

I would suggest you parse the data into a Map<String, Double>. The parsing can easily be done by regexes, e.g. the pattern \G \s*\[\s* ([^=]+) \s*=\s* ([^\]]*) \s*\]\s* (spaces are insignificant – use the Pattern.COMMENTS flag). This is laxer than your substr parsing, but is able to reject malformed input. This also asserts that the matches are adjacent, so no junk will be in between.

Next, you iterate through all matches, updating the Map each time. The regex does not attempt to parse valid doubles – I'd let possible NumberFormatExceptions from Double.parseDouble(...) bubble up. Likewise, you should complain when the parsed data does not contain value, param and indicator fields. Note that this is a semantic constraint that should be tested after the parsing.

I won't show a reimplementation taking these points into consideration because BjoernH's answer already implements the relevant points.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.