So I come from a C background (originally originally, though I haven\'t used that language for almost 5 years) and I\'m trying to parse some values from a string in Java. In
None of these examples were really satisfactory to me so I made my own java sscanf utility:
https://github.com/driedler/java-sscanf/tree/master/src/util/sscanf
Here's an example of parsing a hex string:
String buffer = "my hex string: DEADBEEF\n"
Object output[] = Sscanf.scan(buffer, "my hex string: %X\n", 1);
System.out.println("parse count: " + output.length);
System.out.println("hex str1: " + (Long)output[0]);
// Output:
// parse count: 1
// hex str1: 3735928559
The problem is Java hasn't out parameters (or passing by reference) as C or C#.
But there is a better way (and more solid). Use regular expressions:
Pattern p = Pattern.compile("(\\d+)-(\\p{Alpha}+)-(\\d+) (\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)")
Matcher m = p.matcher("17-MAR-11 15.52.25.000000000");
day = m.group(1);
month= m.group(2);
....
Of course C code is more concise, but this technique has one profit: Patterns specifies format more precise than '%s' and '%d'. So you can use \d{2} to specify that day MUST be compose of exactly 2 digits.
Here is a solution using scanners:
Scanner scanner = new Scanner("17-MAR-11 15.52.25.000000000");
Scanner dayScanner = new Scanner(scanner.next());
Scanner timeScanner = new Scanner(scanner.next());
dayScanner.useDelimiter("-");
System.out.println("day=" + dayScanner.nextInt());
System.out.println("month=" + dayScanner.next());
System.out.println("year=" + dayScanner.nextInt());
timeScanner.useDelimiter("\\.");
System.out.println("hour=" + timeScanner.nextInt());
System.out.println("min=" + timeScanner.nextInt());
System.out.println("sec=" + timeScanner.nextInt());
System.out.println("fracpart=" + timeScanner.nextInt());
This is far from as elegant solution as one would get with using regex, but ought to work.
public static void stringStuffThing(){
String x = "17-MAR-11 15.52.25.000000000";
String y[] = x.split(" ");
for(String s : y){
System.out.println(s);
}
String date[] = y[0].split("-");
String values[] = y[1].split("\\.");
for(String s : date){
System.out.println(s);
}
for(String s : values){
System.out.println(s);
}
Are you familiar with the concept of regular expressions? Java provides you with the ability to use regex by using the Pattern class. Check this one out: http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
You can test your String like that:
Matcher matcher = Pattern.match(yourString);
matcher.find();
and then use the methods provided by Matcher to manipulate the string you found or NOT.
2019 answer: Java's Scanner is flexible for reading a wide range of formats. But if your format has simple {%d, %f, %s} fields then you can scan easily with this small class (~90 lines):
import java.util.ArrayList;
/**
* Basic C-style string formatting and scanning.
* The format strings can contain %d, %f and %s codes.
* @author Adam Gawne-Cain
*/
public class CFormat {
private static boolean accept(char t, char c, int i) {
if (t == 'd')
return "0123456789".indexOf(c) >= 0 || i == 0 && c == '-';
else if (t == 'f')
return "-0123456789.+Ee".indexOf(c) >= 0;
else if (t == 's')
return Character.isLetterOrDigit(c);
throw new RuntimeException("Unknown format code: " + t);
}
/**
* Returns string formatted like C, or throws exception if anything wrong.
* @param fmt format specification
* @param args values to format
* @return string formatted like C.
*/
public static String printf(String fmt, Object... args) {
int a = 0;
StringBuilder sb = new StringBuilder();
int n = fmt.length();
for (int i = 0; i < n; i++) {
char c = fmt.charAt(i);
if (c == '%') {
char t = fmt.charAt(++i);
if (t == 'd')
sb.append(((Number) args[a++]).intValue());
else if (t == 'f')
sb.append(((Number) args[a++]).doubleValue());
else if (t == 's')
sb.append(args[a++]);
else if (t == '%')
sb.append(t);
else
throw new RuntimeException("Unknown format code: " + t);
} else
sb.append(c);
}
return sb.toString();
}
/**
* Returns scanned values, or throws exception if anything wrong.
* @param fmt format specification
* @param str string to scan
* @return scanned values
*/
public static Object[] scanf(String fmt, String str) {
ArrayList ans = new ArrayList();
int s = 0;
int ns = str.length();
int n = fmt.length();
for (int i = 0; i < n; i++) {
char c = fmt.charAt(i);
if (c == '%') {
char t = fmt.charAt(++i);
if (t=='%')
c=t;
else {
int s0 = s;
while ((s == s0 || s < ns) && accept(t, str.charAt(s), s - s0))
s++;
String sub = str.substring(s0, s);
if (t == 'd')
ans.add(Integer.parseInt(sub));
else if (t == 'f')
ans.add(Double.parseDouble(sub));
else
ans.add(sub);
continue;
}
}
if (str.charAt(s++) != c)
throw new RuntimeException();
}
if (s < ns)
throw new RuntimeException("Unmatched characters at end of string");
return ans.toArray();
}
}
For example, the OP's case can be handled like this:
// Example of "CFormat.scanf"
String str = "17-MAR-11 15.52.25.000000000";
Object[] a = CFormat.scanf("%d-%s-%d %d.%d.%f", str);
// Pick out scanned fields
int day = (Integer) a[0];
String month = (String) a[1];
int year = (Integer) a[2];
int hour = (Integer) a[3];
int min = (Integer) a[4];
double sec = (Double) a[5];
// Example of "CFormat.printf"
System.out.println(CFormat.printf("Got day=%d month=%s hour=%d min=%d sec=%f\n", day, month, year, hour, min, sec));