braju.com Java fprintf, printf, sprintf (fscanf, scanf, sscanf)

 

Home

Download
Purchase
History
Examples
Documentation
API/javadoc
FAQ
Feedback
About

Donate

Java scanf

Introduction to Java scanf

In addition to powerful text formatting methods (printf, sprintf and fprintf), the package also provides powerful methods for parsing text (scanf, sscanf, fscanf). In this document, an introduction to formatted input of some of Java's datatype is given with help of examples. The scanf methods are inspired and very look-a-like to the equally named methods found in the C-language. (about 1300 words)

Note: Since scanf() is currently in a beta development phase, all classes is placed under com.braju.beta. When they are matured and well tested they will be upgraded to com.braju. Both scanf() and printf() make use of a new internal class structure which means that also printf() undergoes a beta phase and are hence also placed under com.braju.beta. If you have the stable Java printf package installed, this means that, if you don't "trust" the new printf() method, you can access the well tested one by explicitly write com.braju.Format.printf(...).

Who are you?

We start with a very simple example where we ask the user to enter his/her first name. We then reply the user by saying hello.

 1 import com.braju.beta.format.*;
 2 import com.braju.beta.lang.*;
 3 
 4 public class WhoAreYou {
 5   public static void main(String args[]) throws Exception {
 6     Variable name = new StringVariable();
 7     
 8     Format.printf("Enter your first name: ");
 9     Format.scanf("%s", new Parameters(name));
10     
11     Format.printf("Hello %s!\n", new Parameters(name));   
12   }
13 }

To use scanf one has to make two imports: i) import com.braju.format.* and import com.braju.lang.* (see line 1 and 2). On line 6 an instance of a StringVariable named name is created. Note that we can not use java.lang.String since a String object can not change it value after initializion. On line 8 a printf statement ask the user for its name. The scanf method on line 9 will then read the next string (%s) and store the result in the variable name. The rule for the format flag %s is to first skip all whitespaces (tab, newline, space etc), then read all characters until a whitespace (or end of file) is reached. Note that this means that the name entered can not contain any spaces. In the next example we will show how to deal with string containing spaces. On line 11, we say hello to the user. The toString() method of name is used internally by printf. Here is a run of the program:

Enter your first name: Henrik
Hello Henrik!

Note:When starting a Java application for a shell the InputStream System.in contains a carrage return for some unknown reason (probably due to the shell environment and not to Java). This is the reason for the prompt to occur on the next line and not after the colon. It is important that you are aware of this strange behavior and it is not a bug in the package.

A better Who are you?

 1 import com.braju.beta.format.*;
 2 import com.braju.beta.lang.*;
 3 
 4 public class WhoAreYou2 {
 5   public static void main(String args[]) throws Exception {
 6     Variable name = new StringVariable();
 7     
 8     Format.printf("Enter your first and last name: ");
 9     Format.scanf(" %[^\n]", new Parameters(name));
10     
11     Format.printf("Hello %s!\n", new Parameters(name));
12   }
13 }

We have modified the program to ask for the full name (line 8). As seen in line 9, we are now introducing a new format flag that does not have any corresponding existance for printf. The format flag is a set formatter. A set format flag is as all flags started with a % followed by a sequence of characters between an open and a closing bracket, e.g. here %[^\n]. The ^ denotes not or excluding. The \n is the regular line feed character (LF). This specific format flag defines the rule: read the string of all characters until reaching a new line character, i.e. all characters until the end of line will be read into the variable name. Note that also whitespaces will be read in this case. The set format flag is also special in the way that initial whitespaces will not be skipped as it was in the case for %s and for most other format flags. To skip initial whitespaces we preceed the format flag with a space. When scanf sees one or more spaces in the format string, it will match these with any number of whitespaces.

Enter your first and last name: Henrik Bengtsson
Hello Henrik Bengtsson!

Asking for a number too

Note that the variable name in the above examples is not a String, but a StringVariable. StringVariables have similar functions as Strings. The main difference is that a StringVariable can modify its value, whereas a String can not. Note however that the StringVariable class does not inherit from the String class (since the latter is declared final). To get a String instance of name, we can simply use the toString() method.

 1 import com.braju.beta.format.*;
 2 import com.braju.beta.lang.*;
 3 
 4 public class WhoAreYou3 {
 5   public static void main(String args[]) throws Exception {
 6     Variable nameV = new StringVariable();
 7     Format.printf("Enter your first and last name: ");
 8     Format.scanf(" %[^\n]", new Parameters(nameV));
 9     String name = nameV.toString();
10 
11     IntegerVariable ageV  = new IntegerVariable();
12     Format.printf("%s, how old are you: ", new Parameters(name));
13     Format.scanf("%d", new Parameters(ageV));
14     int age = ageV.intValue();
15     Format.printf("%s, next year you will be %d.\n",
16       new Parameters(name).add(age+1));
17   }
18 }

In this example, we are also introduction a new Variable type called IntegerVariable (line 11). The IntegerVariable class is similar to the Integer class, but as before it is important to remember that it does not inherit from it. On line 13, we are reading the next integer (specified by the %d flag). As in the case of %s, all preceeding whitespaces are skipped by this format flag. This is what we mean by reading the next integer. The IntegerVariable class has a method intValue() which allows us to get the value as an int. See line 14. Here is excerpt from a run:

Enter your first and last name: Henrik Bengtsson
Henrik Bengtsson, how old are you: 29
Henrik Bengtsson, next year you will be 30.

Note: The format flags %d and %i does not have the same meaning when used in scanf (compared to printf). By using %d, we are expecting a integer value. By using %i, we are expecting a integer value with any base, e.g. a hexadecimal value, a octal value etc. Hexadecimal values are assumed to be preceeded by a "0x" and octal value are assumed to be preceeded by a "0". Use %d when you know an integer (with base 10) is expected!

Asking for two values at the same time

It is also possible to have more than one format flag per scanf() call. If we for example would like to find the maximum value of two entered values (integer or decimal), we could write:

 1 import com.braju.beta.format.*;
 2 import com.braju.beta.lang.*;
 3 
 4 class FindMax {
 5   public static double max(double number1, double number2) {
 6     if (number1> number2)
 7       return number1; 
 8     else 
 9       return number2;
10   }
11 
12   public static void main(String args[]) throws Exception {
13     Parameters p = new Parameters();
14     NumberVariable[] dV = DoubleVariable.newArray(2);
15     Format.printf("Enter two values: "); 
16     Format.scanf("%f %f", p.add(dV[0]).add(dV[1])); 
17     double max = max(dV[0].doubleValue(),dV[1].doubleValue());
18     Format.printf("The max of the two is %.2f.\n", p.add(max)); 
19   }
20 }

A run of the program can look as below. Note that the user could enter the values on seperate lines. The only this scanf() cares about is that there is whitespace between the values.

Enter two values: 244.3 43
The max of the two is 244.30.

Note two interesting things in the source code. First, all classes with a suffix Variable has a static method called newArray(int), which creates and instantiates an array of objects from that class. When you write more extensive applications, you believe you will find this useful. Second, for our example it is actually not of interest to declare dV to be DoubleVariable[]; it is enough to use the super class.

Java reflection approach

If you think the Variable approach is too awkward, Java scanf() let you store the results in fields using Java reflection (since JDK 1.1). You simply pass scanf() (1) an object and (2) the field name (as a String) in that object where you want to store the result. The field must be declared public. Example: Example:

 1 import com.braju.beta.format.*;
 2 
 3 public class PersonReflect {
 4   private Parameters p = new Parameters();
 5   public String name;
 6   public int age;
 7 
 8   public void query() throws Exception {
 9     Format.printf("Enter your full name: ");
10     Format.scanf(" %[^\n]", p.add(this).add("name"));
11     Format.printf("Enter your age (in years): ");
12     Format.scanf("%i", p.add(this).add("age"));
13   }
14   
15   public void display() {
16     Format.printf("Hello %s, you are %i years old.\n", 
17       p.add(name).add(age));
18   }
19   
20   public static void main(String args[]) throws Exception {
21     PersonReflect currPerson = new PersonReflect();
22     currPerson.query();
23     currPerson.display();
24   }
25 }

Enter your full name: Henrik Bengtsson
Enter your age (in years): 29
Hello Henrik Bengtsson, you are 29 years old.

Note that this approach does not work with local variables (since they are not seen by the Java reflection methods).

 1 Format.scanf("Enter x and y coordinate: ", p.add(this).add("x").add("y"));

You should be aware that using the Java reflection approach, there is no way for the compiler to tell if the field you give exists or not. If you give a non-existing name or its datatype is compatible with scanf's result, an exception will be thrown.

If you are having several field names, scanf() will remember the last object passed to it. In other words, you only have to specify the object once per scanf() call. You can also declare a Parameters that always remembers the object whose fields should be updated by scanf(). This can be done by first adding the object and the call mark() on the Parameters object. Example:

 1 Parameters ps = new Parameters(this).mark();

This will protect "this" from being removed. After scanf() (and also printf()) are done they call the reset() method of the Parameters object. The reset() method is defined to remove all parameters after a mark. If there is no mark, all parameters are removed. If you would like to remove a mark, just call unmark(). Using this feature, the above code can be simplified a little bit more.

 1 import com.braju.beta.format.*;
 2 
 3 public class PersonReflect2 {
 4   // Parameters to be used by scanf() with "this" always preset.
 5   private Parameters ps = new Parameters(this).mark();
 6   // Parameters to be used by printf().
 7   private Parameters p = new Parameters();
 8   public String name;
 9   public int age;
10 
11   public void query() throws Exception {
12     Format.printf("Enter your full name: ");
13     Format.scanf(" %[^\n]", ps.add("name"));
14     Format.printf("Enter your age (in years): ");
15     Format.scanf("%i", ps.add("age"));
16   }
17   
18   public void display() {
19     Format.printf("Hello %s, you are %i years old.\n", 
20       p.add(name).add(age));
21   }
22   
23   public static void main(String args[]) throws Exception {
24     PersonReflect2 currPerson = new PersonReflect2();
25     currPerson.query();
26     currPerson.display();
27   }
28 }

Conclusion

Since Java lacks pointers (luckily) we have to use wrappers explicitly for scanf(). All the wrappers understood by scanf() are all named as the conventional Java datatype wrappers with the suffix Variable, e.g. IntegerVariable. To get the int value of an IntegerVariable we have to use the intValue() method. This makes the scanf() approach in Java a little bit more "code" consuming than what you might be used to from C, and an option is to make use of Java reflection. Otherwise, Java scanf() works as you should expect.