3

I'm wondering if there is any nice way how to read single attributes from formatted string in Groovy or even in Java.

I have a string containing some attributes separated by space. For example "2.1 20 Something true". The order is fixed and the "attribute type" is known (for the example first is Float, second is Integer, etc.). I need something similar to String.format() but other way round.

I know that I can split the string manually and read the values, but this makes the code too complicated like this:

String[] parsedText = "2.1 20 Something true".split(delimiter)

try {
   firstVal = new Float(parsedText[0])
}
catch (NumberFormatException e) {
   throw new RuntimeException("Bad data [0th position in data string], cannot read[{$parsedData[0]}], cannot convert to float")
}
...

Is there a better way? I'm pretty sure that at least in Groovy is:-)

Thanks!

2 Answers 2

11

The Java Scanner class has a whole bunch of methods for grabbing and parsing the next part of a string, e.g. next(), nextInt(), nextDouble(), etc.

The code looks like this:

String input = "2.1 20 Something true";
Scanner s = new Scanner(input);
float f = s.nextFloat();
int i = s.nextInt();
String str = s.next(); // next() doesn't parse, you automatically get a string
boolean b = s.nextBoolean();

Only thing to be wary of: next() and nextLine() both get you strings, but next() only gets you the string up to the next space. If you want your string components to have spaces in them you'll need to account for that.

Sign up to request clarification or add additional context in comments.

Comments

2

Scanner class from java.util should do the job for you. While reading from input there is much more cases which you need to be taken into account.

In your case you can call scanner methods in a row or use regexp to have "format string" explicitly defined and keep it tided in one place. In this way you will benefit by having validation at once.

//calling methods in row
{
    Scanner sc = new Scanner("2.1 20 Something true");
    float f = sc.nextFloat();
    int i = sc.nextInt();
    String s = sc.nextLine();

    System.out.print(String.format("%s\t%.2f\t%x\n", s, f, i));

    sc.close();
}
//using regexp
{
    Scanner sc = new Scanner("2.1 20 Something true");
    sc.findInLine("(\\d+[\\.,]?\\d*)\\s(\\d+)(\\s.*)$");
    MatchResult result = sc.match();
    float f = Float.parseFloat(result.group(1));
    int i = Integer.parseInt(result.group(2));
    String s = result.group(3);

    System.out.print(String.format("%s\t%.2f\t%x\n", s, f, i));

    sc.close();
}

Scanner class has different constructors to use the class with objects of type: File, InputStream, Readable, ReadableByteChannel and as spotted in example with String.

Be aware that this class is locale aware so it may behaves differently depends on system settings (some countries use coma instead point for floating point, etc ...). You can override locale settings.

Here is comprehensive reference: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Scanner.html

1 Comment

"Something true" is actually supposed to be a string followed by a boolean, not a two-word string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.