什么是sscanf的Java等价物,用于使用已知模式解析字符串中的值?

时间:2011-12-08 11:10:01

标签: java scanf

所以我来自C背景(原来最初,虽然我已经有近5年没用过那种语言了)而且我正在尝试从Java中的字符串中解析一些值。在C中我会使用sscanf。在Java中,人们告诉我“使用Scanner或StringTokenizer”,但我看不出如何使用它们来实现我的目的。

我的输入字符串看起来像“17-MAR-11 15.52.25.000000000”。在C中我会做类似的事情:

sscanf(thestring, "%d-%s-%d %d.%d.%d.%d", day, month, year, hour, min, sec, fracpart);

但在Java中,我所能做的就是:

scanner.nextInt();

这不允许我检查模式,对于“MAR”我最终不得不做以下事情:

str.substring(3,6);

可怕!当然有更好的方法吗?

8 个答案:

答案 0 :(得分:39)

问题是Java没有输出参数(或通过引用传递)为C或C#。

但是有一种更好的方式(更稳固)。使用正则表达式:

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

当然C代码更简洁,但这种技术有一个好处: 模式指定的格式比'%s'和'%d'更精确。因此,您可以使用\ d {2}指定那天必须完全由2位数组成。

答案 1 :(得分:22)

以下是使用扫描仪的解决方案:

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

答案 2 :(得分:11)

这些例子都不是我真正满意所以我自己制作了java sscanf实用程序:

https://github.com/driedler/java-sscanf/tree/master/src/util/sscanf

以下是解析十六进制字符串的示例:

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

答案 3 :(得分:3)

对于“17-MAR-11 15.52.25.000000000”:

SimpleDateFormat format = new SimpleDateFormat("dd-MMM-yy HH.mm.ss.SSS");

try 
{
    Date parsed = format.parse(dateString);
    System.out.println(parsed.toString());
}
catch (ParseException pe)
{
    System.out.println("ERROR: Cannot parse \"" + dateString + "\"");
}

答案 4 :(得分:2)

这远不像使用正则表达式那样优雅的解决方案,但应该有效。

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

答案 5 :(得分:0)

您熟悉正则表达式的概念吗? Java为您提供了使用Pattern类来使用正则表达式的功能。 检查一下: http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html

你可以像这样测试你的字符串:

Matcher matcher = Pattern.match(yourString);
matcher.find();

然后使用Matcher提供的方法来操作你找到的字符串或不用。

答案 6 :(得分:0)

2019年答案:Java的Scanner灵活,可读取各种格式。但是,如果您的格式具有简单的{%d,%f,%s}字段,则可以使用此小类(〜90行)轻松进行扫描:

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

例如,OP的情况可以这样处理:

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

答案 7 :(得分:-3)

System.in.read()是另一种选择。