what is the Java equivalent of sscanf for parsing values from a string using a known pattern?

后端 未结 8 859
梦如初夏
梦如初夏 2020-11-27 06:01

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

8条回答
  •  长情又很酷
    2020-11-27 06:53

    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));
    

提交回复
热议问题