Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/hartmath/lib/Formatter.java


1   package com.hartmath.lib;
2   
3   
4   /** 
5    *
6    * This class provides C-like formatting functions that allow
7    * programmers to convert an integer or floating point number
8    * into a string with a specified, width, precision and format. 
9    * For instance this might be used to format monetary data to 
10   * two decimal places.<P>
11   *
12   * Because Java does not have variable length argument lists like C,
13   * a different strategy must be employed. Each number is passed
14   * to a format() method along with formatting instructions. The format()
15   * method returns a formatted string which may then be passed to
16   * System.out.println() or other methods. In short this is more
17   * similar to C's sprintf() than to printf(). <P>
18   *
19   * There are a number of possible things one can do when a number
20   * will not fit inside the specified format. You can throw an exception,
21   * truncate the number, return an error string, or expand the width.
22   * Here I've chosen to expand the width. <P>
23   *
24   * The rounding of these precisions still needs work. Currently 
25   * excess digits are merely truncated.<P>
26   *
27   * @Version: 0.1 of August 11, 1997
28   * @Author: Elliotte Rusty Harold (elharo@sunsite.unc.edu)
29   */
30   
31  public class Formatter {
32  
33    /* Since this class only contains static utility methods there's
34    no reason to allow instances of it to be created */
35    
36    private Formatter() {
37    }
38    
39    // longs and ints have different default widths,
40    // otherwise they're treated the same
41    // I used the maximum necessary widths for the type. An
42    // alternative soultion would be to use only as many characters 
43    // as necessary
44  
45    /** 
46     *
47     * This method formats an int in 10 characters
48     * with no leading zeroes,
49     * right aligned, without +
50     * signs on positive numbers, filled out to the specified width
51     * with spaces
52     *
53     * @param d The number to be formatted
54     * @return A String containing a formatted representation of the number
55     */
56    public static String format(int i) {
57      return format(i, 11, -1, false, false, ' ', 10);
58    }
59  
60    /** 
61     *
62     * This method formats a long in 20 characters
63     * with no leading zeroes,
64     * right aligned, without +
65     * signs on positive numbers, filled out to the specified width
66     * with spaces
67     *
68     * @param d The number to be formatted
69     * @return A String containing a formatted representation of the number
70     */
71    public static String format(long l) {
72      return format(l, 20, -1, false, false, ' ', 10);
73    }
74  
75    // Rather than providing all possible permutations of arguments
76    // (64 in this case) it's customary to provide the most common
77    // options in the most common order
78  
79    /** 
80     *
81     * This method formats an integer to a specified width,
82     * no leading zeroes,
83     * right aligned, without +
84     * signs on positive numbers, filled out to the specified width
85     * with spaces
86     *
87     * @param d The number to be formatted
88     * @param width The minimum number of characters in the returned string
89     * @return A String containing a formatted representation of the number
90     */
91    public static String format(long l, int width) {
92      return format(l, width, -1, false, false, ' ', 10);
93    }
94  
95    /** 
96     *
97     * This method formats an integer to a specified width,
98     * number of leading zeroes,
99     * right aligned, without +
100    * signs on positive numbers, filled out to the specified width
101    * with spaces
102    *
103    * @param d The number to be formatted
104    * @param width The minimum number of characters in the returned string
105    * @param precision The number of leading zeroes
106    * @return A String containing a formatted representation of the number
107    */
108   public static String format(long l, int width, int precision) {
109     return format(l, width, precision, false, false, ' ', 10);
110   }
111 
112   /** 
113    *
114    * This method formats an integer to a specified width,
115    * number of leading zeroes,
116    * aligned left or right, without +
117    * signs on positive numbers, filled out to the specified width
118    * with spaces
119    *
120    * @param d The number to be formatted
121    * @param width The minimum number of characters in the returned string
122    * @param precision The number of leading zeroes
123    * @param alignLeft True for left alignment in the width, 
124    * false for right alignment
125    * @return A String containing a formatted representation of the number
126    */
127   public static String format(long l, int width, int precision, 
128    boolean alignLeft) {
129     return format(l, width, precision, alignLeft, false, ' ', 10);
130   }
131 
132   /** 
133    *
134    * This method formats an integer to a specified width,
135    * number of leading zeroes,
136    * aligned left or right, with or without +
137    * signs on positive numbers, filled out to the specified width
138    * with spaces
139    *
140    * @param d The number to be formatted
141    * @param width The minimum number of characters in the returned string
142    * @param precision The number of leading zeroes
143    * @param alignLeft True for left alignment in the width, 
144    * false for right alignment
145    * @param usePlus True if positive numbers are prefixed with + signs
146    * @return A String containing a formatted representation of the number
147    */
148   public static String format(long l, int width, int precision, 
149    boolean alignLeft, boolean usePlus) {
150     return format(l, width, precision, alignLeft, usePlus, ' ', 10);
151   }
152 
153   /** 
154    *
155    * This method formats an integer to a specified width,
156    * number of leading zeroes,
157    * aligned left or right, with or without +
158    * signs on positive numbers, with a user-specified padding 
159    * character used to fill out the number to the specified width.
160    *
161    * @param d The number to be formatted
162    * @param width The minimum number of characters in the returned string
163    * @param precision The number of leading zeroes
164    * @param alignLeft True for left alignment in the width, 
165    * false for right alignment
166    * @param usePlus True if positive numbers are prefixed with + signs
167    * @param pad The character used to fill out the number 
168    * to the specified width
169    * @return A String containing a formatted representation of the number
170    */
171   public static String format(long l, int width, 
172    int precision, boolean alignLeft, 
173    boolean usePlus, char pad) {
174     return format(l, width, precision, alignLeft, usePlus, pad, 10);
175   }
176 
177   /** 
178    *
179    * This method formats an integer to a specified width,
180    * number of leading zeroes,
181    * aligned left or right, with or without +
182    * signs on positive numbers, with a user-specified padding 
183    * character used to fill out the number to the specified width,
184    * in a specified base
185    *
186    * @param d The number to be formatted
187    * @param width The minimum number of characters in the returned string
188    * @param precision The number of leading zeroes
189    * @param alignLeft True for left alignment in the width, 
190    * false for right alignment
191    * @param usePlus True if positive numbers are prefixed with + signs
192    * @param pad The character used to fill out the number 
193    * to the specified width
194    * @param radix The base in which numbers are formatted; e.g. 8, 10, 16
195    * @return A String containing a formatted representation of the number
196    */
197   public static String format(long l, int width, 
198    int precision, boolean alignLeft, 
199    boolean usePlus, char pad, int radix) {
200   
201     // Do the initial conversion
202     String s = Long.toString(Math.abs(l), radix);
203     
204     // add leading zeroes if necessary
205     if (precision > s.length()) {
206        int padLength = precision - s.length();
207        String zeroes = "";
208        for (int i = 0; i < padLength; i++) zeroes += '0';
209        s = zeroes + s;
210     }
211     
212     // add the sign
213     if (usePlus && l > 0) s = '+' + s;
214     else if (l < 0) s = '-' + s;
215     else s = ' ' + s;
216 
217     if (s.length() < width) {
218        int padLength = width - s.length();
219        String padding = "";
220        for (int i = 0; i < padLength; i++) padding += pad;
221        if (alignLeft) s += padding;
222        else s = padding + s;
223     }
224     
225     return s;
226 
227   }
228 
229   /** 
230    *
231    * This method formats a floating point number to a minimum of 12 characters,
232    * six decimal places, in decimal format,
233    * right aligned, without +
234    * signs on positive numbers. Spaces 
235    * fill out the number to the specified width.
236    *
237    * @param d The number to be formatted
238    * @return A String containing a formatted representation of the number.
239    */
240   public static String format(double d) {
241     return format(d, 12, 6, false, false, false, ' ');
242   }
243 
244   /** 
245    *
246    * This method formats a floating point number to specified width,
247    * six decimal places, in decimal format,
248    * right aligned, without +
249    * signs on positive numbers. Spaces 
250    * fill out the number to the specified width.
251    *
252    * @param d The number to be formatted
253    * @param width The minimum number of characters in the returned string
254    * @return A String containing a formatted representation of the number.
255    */
256   public static String format(double d, int width) {
257     return format(d, width, 6, false, false, false, ' ');
258   }
259 
260   /** 
261    *
262    * This method formats a floating point number to specified width,
263    * number of decimal places, in decimal format,
264    * right aligned, without +
265    * signs on positive numbers. Spaces 
266    * fill out the number to the specified width.
267    *
268    * @param d The number to be formatted
269    * @param width The minimum number of characters in the returned string
270    * @param precision The number of digits after the decimal point
271    * @return A String containing a formatted representation of the number.
272    */
273   public static String format(double d, int width, int precision) {
274     return format(d, width, precision, false, false, false, ' ');
275   }
276 
277   /** 
278    *
279    * This method formats a floating point number to specified width,
280    * number of decimal places, in exponential or decimal format,
281    * right aligned, without +
282    * signs on positive numbers. Spaces 
283    * fill out the number to the specified width.
284    *
285    * @param d The number to be formatted
286    * @param width The minimum number of characters in the returned string
287    * @param precision The number of digits after the decimal point
288    * @param exponential true if the number is to be displayed in 
289    * exponential notation, e.g. 3.50E+09, false otherwise
290    * @return A String containing a formatted representation of the number.
291    */
292   public static String format(double d, int width, 
293    int precision, boolean exponential) {
294     return format(d, width, precision, exponential, false, false, ' ');
295   }
296 
297   /** 
298    *
299    * This method formats a floating point number to a specified width,
300    * number of decimal places, in exponential or decimal format,
301    * aligned left or right, without +
302    * signs on positive numbers. Spaces 
303    * fill out the number to the specified width.
304    *
305    * @param d The number to be formatted
306    * @param width The minimum number of characters in the returned string
307    * @param precision The number of digits after the decimal point
308    * @param exponential true if the number is to be displayed in 
309    * exponential notation, e.g. 3.50E+09, false otherwise
310    * @param alignLeft True for left alignment in the width, 
311    * false for right alignment
312    * @return A String containing a formatted representation of the number.
313    */
314   public static String format(double d, int width, 
315    int precision, boolean exponential, boolean alignLeft) {
316     return format(d, width, precision, exponential, alignLeft, false, ' ');
317   }
318 
319   /** 
320    *
321    * This method formats a floating point number to a specified width,
322    * number of decimal places, in exponential or decimal format,
323    * aligned left or right, with or without +
324    * signs on positive numbers. Spaces 
325    * fill out the number to the specified width.
326    *
327    * @param d The number to be formatted
328    * @param width The minimum number of characters in the returned string
329    * @param precision The number of digits after the decimal point
330    * @param exponential true if the number is to be displayed in 
331    * exponential notation, e.g. 3.50E+09, false otherwise
332    * @param alignLeft True for left alignment in the width, 
333    * false for right alignment
334    * @param usePlus True if positive numbers are prefixed with + signs
335    * @return A String containing a formatted representation of the number.
336    */
337   public static String format(double d, int width, 
338    int precision, boolean exponential, boolean alignLeft, 
339    boolean usePlus) {
340     return format(d, width, precision, exponential, alignLeft, usePlus, ' ');
341   }
342 
343   // need to round better when truncating precision
344   /** 
345    *
346    * This method formats a floating point number to a specified width,
347    * number of decimal places, in exponential or decimal format,
348    * aligned left or right, with or without +
349    * signs on positive numbers, and with a user-specified padding 
350    * character used to fill out the number to the specified width.
351    *
352    * @param d The number to be formatted
353    * @param width The minimum number of characters in the returned string
354    * @param precision The number of digits after the decimal point
355    * @param exponential true if the number is to be displayed in 
356    * exponential notation, e.g. 3.50E+09, false otherwise
357    * @param alignLeft True for left alignment in the width, 
358    * false for right alignment
359    * @param usePlus True if positive numbers are prefixed with + signs
360    * @param pad The character used to fill out the number 
361    * to the specified width
362    * @return A String containing a formatted representation of the number.
363    */
364   public static String format(double d, int width, 
365    int precision, boolean exponential, boolean alignLeft, 
366    boolean usePlus, char pad) {
367 
368     String s = "";
369     
370     // find mantissa and exponent
371     double y = Math.abs(d);
372     String mantissa;
373     int exponent;
374          
375     if (Double.isInfinite(y)) {
376       s = "Inf";    
377     }
378     else if (Double.isNaN(y)) {
379       s = "NaN";
380     }
381     else {  // find mantissa and exponent
382       s = Double.toString(y);
383       int e = s.toUpperCase().indexOf('E');
384       if (e != -1) { // in exponential form
385         mantissa = s.substring(0, e);
386         // remove the decimal point
387         // which is always to the right of the first digit
388         mantissa = mantissa.charAt(0) + mantissa.substring(2);
389         exponent = Integer.parseInt(s.substring(e+1)); 
390       }  // end exponential form
391       else { // in decimal form to start with
392         int decimalpoint = s.indexOf('.');
393         mantissa = s.substring(0, decimalpoint) + s.substring(decimalpoint+1);
394         // find first non-zero digit
395         int r = -1;
396         for (int i = 0; i < s.length(); i++) {
397           char c = s.charAt(i);
398           if (c != '0' && Character.isDigit(c)) {
399             r = i;
400             break;
401           }
402         }
403         if (r == -1) { // this has to zero
404           exponent = 0;
405         }
406         else {
407           if (r < decimalpoint) exponent = decimalpoint - r - 1;
408           else exponent = decimalpoint - r;
409         }        
410       } // end decimal form
411         
412       if (exponential) {
413         while (mantissa.length() < precision + 1) mantissa += '0';
414         s = mantissa.charAt(0) + "." + mantissa.substring(1,precision+1);
415         String exponentString = "E";
416         if (exponent >= 0) exponentString += "+";
417         else exponentString += "-";
418         if (Math.abs(exponent) < 10) exponentString += "0";
419         exponentString += Math.abs(exponent);    
420         s += exponentString;  
421       }
422       else { // use decimal notation
423         // convert the exponent to a decimal point
424         // with extra zeroes if necessary
425         if (exponent < 0) {
426           String prefix = "0.";
427           for (int i = exponent; i < -1; i++) prefix += '0';
428           s = prefix + mantissa;
429           if (precision >= 0) s = s.substring(0, precision+3);
430         }
431         else if (exponent < mantissa.length()-1 ) {
432           s = mantissa.substring(0, exponent+1) + '.' 
433            + mantissa.substring(exponent+1);
434            if (precision >= 0) {
435              int end = exponent + 1 + precision;
436              if (end < s.length()) s = s.substring(0, end+1);
437              else {
438                for (int i = 0; i < end - s.length() + 1; i++) s += '0';             
439              }
440            }
441         }
442         else { // exponent >= mantissa.length()
443           s = mantissa;
444           for (int i = 0; i < exponent - mantissa.length() + 1; i++) s += '0';
445           s += ".";
446           for (int i = 0; i < precision; i++) s += '0';
447         }        
448       }  
449     }  
450     
451     
452     // add the sign
453     if (d < 0) s = '-' + s;
454     else if (d == 0.0) s = ' ' + s;
455     // > 0 is not superfluous due to NaN
456     else if (usePlus && d > 0) s = '+' + s;
457     
458     // expand the width
459     if (s.length() < width) {
460        int padLength = width - s.length();
461        String padding = "";
462        for (int i = 0; i < padLength; i++) padding += pad;
463        if (alignLeft) s += padding;
464        else s = padding + s;
465     }
466     
467     return s;
468 
469   }
470   
471   
472   // still need to handle %g
473   /** 
474    *
475    * This method formats a floating point number to a specified width,
476    * number of leading zeroes,
477    * aligned left or right, with or without +
478    * signs on positive numbers, with a user-specified padding 
479    * character used to fill out the number to the specified width,
480    * in a specified base using a C-like formatting string such as 
481    * %5f, %15.4F, %-15.3E, %.10f, and so on.<P>  
482    * Currently only
483    * f, F, e, and E formats are supported. g and G formats are not supported
484    *
485    * @param d The number to be formatted
486    * @param s A String containing formatting instructions
487    * @return A String containing a formatted representation of the number
488    */
489   public static String format(double d, String s) {
490    
491     int width = -1;
492     int precision = 6; 
493     boolean exponential = false;
494     boolean alignLeft = false;    
495     boolean usePlus = false; 
496     
497     if (s.charAt(0) == '%') s = s.substring(1);
498     if (s.charAt(0) == '-') {
499       alignLeft = true;
500       s = s.substring(1);
501     }
502     if (s.toUpperCase().endsWith("E")) exponential = true;
503     int period = s.indexOf(".");
504     if (period != -1) {
505       try {
506         String prec = s.substring(period+1, s.length()-1);
507         precision = Integer.parseInt(prec);
508       } 
509       catch (Exception e) {
510       } 
511       try {
512         String w = s.substring(0, period);
513         width = Integer.parseInt(w);
514       } 
515       catch (Exception e) {
516       } 
517     } // end if
518     else {
519       try {
520         String w = s.substring(0, s.length()-1);
521         width = Integer.parseInt(w);
522       } 
523       catch (Exception e) {
524       }       
525     } // end else
526     
527     return format(d, width, precision, exponential, alignLeft, usePlus);
528    
529   }
530   
531   /** 
532    *
533    * This method formats an integer to a specified width,
534    * number of leading zeroes,
535    * aligned left or right, with or without +
536    * signs on positive numbers,
537    * in octal, decimal, or hexadecimal 
538    * using a C-like formatting string such as 
539    * %5d, %15.4d, %-15.3x, %.10X, and so on.<P>  
540    *
541    * @param d The number to be formatted
542    * @param s A String containing formatting instructions
543    * @return A String containing a formatted representation of the number
544    */
545   public static String format(long l, String s) {
546    
547     int width = -1;
548     int precision = 0; 
549     int radix = 10;
550     boolean alignLeft = false; 
551     boolean usePlus = false; 
552     
553     if (s.charAt(0) == '%') s = s.substring(1);
554     if (s.charAt(0) == '-') {
555       alignLeft = true;
556       s = s.substring(1);
557     }
558     if (s.toUpperCase().endsWith("X")) radix = 16;
559     else if (s.toUpperCase().endsWith("O")) radix = 8;
560 
561     int period = s.indexOf(".");
562     if (period != -1) {
563       try {
564         String prec = s.substring(period+1, s.length()-1);
565         precision = Integer.parseInt(prec);
566       } 
567       catch (Exception e) {
568       } 
569       try {
570         String w = s.substring(0, period);
571         width = Integer.parseInt(w);
572       } 
573       catch (Exception e) {
574       } 
575     } // end if
576     else {
577       try {
578         String w = s.substring(0, s.length()-1);
579         width = Integer.parseInt(w);
580       } 
581       catch (Exception e) {
582       }       
583     } // end else
584     
585     return format(l, width, precision, alignLeft, usePlus, ' ', radix);
586    
587   }
588     
589   public static void main(String[] args) {
590   
591     if (args == null || args.length == 0) test();
592     else {
593       for (int i = 0; i < args.length; i++) {
594         long n = 0;
595         double x = 0;
596         try {
597           n = Long.valueOf(args[i]).longValue();
598           testInteger(n);
599         }
600         catch (NumberFormatException e1) {
601           try {
602             x = Double.valueOf(args[i]).doubleValue();
603             testFloatingPoint(x);
604           }
605           catch (NumberFormatException e2) {
606             System.err.println(args[i] + "is not a number.");
607           }
608         }
609       }  // end for
610     
611     } // end else
612   
613   } // end main()
614 
615 
616   private static void test() {
617   
618     for (int i = -10; i <= 10; i+= 5) testInteger(i);
619     for (int i = 1; i < 10; i++) {
620       testInteger((long) Math.floor(Math.random() * 1000000));
621     }
622     testFloatingPoint(7.5);
623     testFloatingPoint(Math.PI);
624     testFloatingPoint(Math.E);
625     testFloatingPoint(897.6);
626     testFloatingPoint(765);
627     testFloatingPoint(-98.765);
628     testFloatingPoint(65.4E23);
629     testFloatingPoint(65.4E-23);
630     testFloatingPoint(-65.4E23);
631     testFloatingPoint(-65.4E-23);
632     testFloatingPoint(0.0);
633     testFloatingPoint(1);
634     testFloatingPoint(Math.sqrt(2));
635     testFloatingPoint(Double.POSITIVE_INFINITY);
636     testFloatingPoint(Double.NEGATIVE_INFINITY);
637     testFloatingPoint(Double.NaN);
638   }
639 
640   private static void testInteger(long n) {
641   
642     String s;
643     s = format(n, 16, 4, false, false, ' ');
644     System.out.print(s);
645     s = format(n, 10, 4, false, false, ' ');
646     System.out.print(s);
647     s = format(n, 4, -1, true, true, '_');
648     System.out.print(s);
649     s = format(n, -1, -1, true, true, ' ');
650     System.out.print(s);
651     System.out.println();
652   
653   }
654 
655   // should also print non-formatted value for comparison
656 
657   private static void testFloatingPoint(double x) {
658 
659     System.out.println("Unformatted: " + x);
660     String s = format(x);
661     System.out.println(s);
662     s = format(x, 10, 4, true);
663     System.out.println(s);
664     
665   }
666 
667 
668 }
669