首页>代码>JAVA.2核心技术.第1卷:基础知识(原书第7版) 源代码>/JAVA.2核心技术.第1卷:基础知识(原书第7版) 源代码/com/horstmann/Format.java
package com.horstmann;

import java.io.*;

/**
   A class for formatting numbers that follows <tt>printf</tt> conventions.

   Also implements C-like <tt>atoi</tt> and <tt>atof</tt> functions

   @version 1.21 2000-06-09
   @author Cay Horstmann

   1998-09-14: Fixed a number of bugs.
        1.Formatting the most extreme negative number (-9223372036854775808L) printed with 2 leading minus signs.
        2.Printing 0 with a %e or %g format did not work.
        3.Printing numbers that were closer to 1 than the number of requested decimal places rounded down rather than up, e.g. formatting 1.999 with %.2f printed 1.00. (This one is pretty serious, of course.)
        4.Printing with precision 0 (e.g %10.0f) didn't work.
        5.Printing a string with a precision that exceeded the string length (e.g. print "Hello" with %20.10s) caused a StringIndexOutOfBounds error.
   1998-10-21: Changed method names from print to printf
   2000-06-09: Moved to package com.horstmann; no longer part of
   Core Java
   2000-06-09: Fixed a number of bugs.
        1.Printing 100.0 with %e printed 10.0e1, not 1.0e2
        2.Printing Inf and NaN didn't work.
   2000-06-09: Coding guideline cleanup
*/
public class Format
{
   /**
      Formats the number following <tt>printf</tt> conventions.
      Main limitation: Can only handle one format parameter at a time
      Use multiple Format objects to format more than one number
      @param s the format string following printf conventions
      The string has a prefix, a format code and a suffix. The prefix and suffix
      become part of the formatted output. The format code directs the
      formatting of the (single) parameter to be formatted. The code has the
      following structure
      <ul>
      <li> a % (required)
      <li> a modifier (optional)
      <dl>
      <dt> + <dd> forces display of + for positive numbers
      <dt> 0 <dd> show leading zeroes
      <dt> - <dd> align left in the field
      <dt> space <dd> prepend a space in front of positive numbers
      <dt> # <dd> use "alternate" format. Add 0 or 0x for octal or hexadecimal numbers. Don't suppress trailing zeroes in general floating point format.
      </dl>
      <li> an integer denoting field width (optional)
      <li> a period followed by an integer denoting precision (optional)
      <li> a format descriptor (required)
      <dl>
      <dt>f <dd> floating point number in fixed format
      <dt>e, E <dd> floating point number in exponential notation (scientific format). The E format results in an uppercase E for the exponent (1.14130E+003), the e format in a lowercase e.
      <dt>g, G <dd> floating point number in general format (fixed format for small numbers, exponential format for large numbers). Trailing zeroes are suppressed. The G format results in an uppercase E for the exponent (if any), the g format in a lowercase e.
      <dt>d, i <dd> integer in decimal
      <dt>x <dd> integer in hexadecimal
      <dt>o <dd> integer in octal
      <dt>s <dd> string
      <dt>c <dd> character
      </dl>
      </ul>
      @exception IllegalArgumentException if bad format
   */
   public Format(String s)
   {
      width = 0;
      precision = -1;
      pre = "";
      post = "";
      leadingZeroes = false;
      showPlus = false;
      alternate = false;
      showSpace = false;
      leftAlign = false;
      fmt = ' ';

      int state = 0;
      int length = s.length();
      int parseState = 0;
      // 0 = prefix, 1 = flags, 2 = width, 3 = precision,
      // 4 = format, 5 = end
      int i = 0;

      while (parseState == 0)
      {
         if (i >= length) parseState = 5;
         else if (s.charAt(i) == '%')
         {
            if (i < length - 1)
            {
               if (s.charAt(i + 1) == '%')
               {
                  pre = pre + '%';
                  i++;
               }
               else
                  parseState = 1;
            }
            else throw new java.lang.IllegalArgumentException();
         }
         else
            pre = pre + s.charAt(i);
         i++;
      }
      while (parseState == 1)
      {
         if (i >= length) parseState = 5;
         else if (s.charAt(i) == ' ') showSpace = true;
         else if (s.charAt(i) == '-') leftAlign = true;
         else if (s.charAt(i) == '+') showPlus = true;
         else if (s.charAt(i) == '0') leadingZeroes = true;
         else if (s.charAt(i) == '#') alternate = true;
         else { parseState = 2; i--; }
         i++;
      }
      while (parseState == 2)
      {
         if (i >= length) parseState = 5;
         else if ('0' <= s.charAt(i) && s.charAt(i) <= '9')
         {
            width = width * 10 + s.charAt(i) - '0';
            i++;
         }
         else if (s.charAt(i) == '.')
         {
            parseState = 3;
            precision = 0;
            i++;
         }
         else
            parseState = 4;
      }
      while (parseState == 3)
      {
         if (i >= length) parseState = 5;
         else if ('0' <= s.charAt(i) && s.charAt(i) <= '9')
         {
            precision = precision * 10 + s.charAt(i) - '0';
            i++;
         }
         else
            parseState = 4;
      }
      if (parseState == 4)
      {
         if (i >= length) parseState = 5;
         else fmt = s.charAt(i);
         i++;
      }
      if (i < length)
         post = s.substring(i, length);
   }

  /**
     prints a formatted number following printf conventions
     @param fmt the format string
     @param x the double to print
   */
   public static void printf(String fmt, double x)
   {
      System.out.print(new Format(fmt).format(x));
   }

   /**
      prints a formatted number following printf conventions
      @param fmt the format string
      @param x the int to print
   */
   public static void printf(String fmt, int x)
   {
      System.out.print(new Format(fmt).format(x));
   }

   /**
      prints a formatted number following printf conventions
      @param fmt the format string
      @param x the long to print
   */
   public static void printf(String fmt, long x)
   {
      System.out.print(new Format(fmt).format(x));
   }

   /**
      prints a formatted number following printf conventions
      @param fmt the format string
      @param x the character to print
   */
   public static void printf(String fmt, char x)
   {
      System.out.print(new Format(fmt).format(x));
   }

   /**
      prints a formatted number following printf conventions
      @param fmt the format string
      @param x a string to print
   */
   public static void printf(String fmt, String x)
   {
      System.out.print(new Format(fmt).format(x));
   }

   /**
      Converts a string of digits (decimal, octal or hex) to an integer
      @param s a string
      @return the numeric value of the prefix of s representing a base 10 integer
   */
   public static int atoi(String s)
   {
      return (int)atol(s);
   }

  /**
     Converts a string of digits (decimal, octal or hex) to a long integer
     @param s a string
     @return the numeric value of the prefix of s representing a base 10 integer
  */
   public static long atol(String s)
   {
      int i = 0;

      while (i < s.length() && Character.isWhitespace(s.charAt(i))) i++;
      if (i < s.length() && s.charAt(i) == '0')
      {
         if (i + 1 < s.length() && (s.charAt(i + 1) == 'x' || s.charAt(i + 1) == 'X'))
            return parseLong(s.substring(i + 2), 16);
         else return parseLong(s, 8);
      }
      else return parseLong(s, 10);
   }

   private static long parseLong(String s, int base)
   {
      int i = 0;
      int sign = 1;
      long r = 0;

      while (i < s.length() && Character.isWhitespace(s.charAt(i))) i++;
      if (i < s.length() && s.charAt(i) == '-') { sign = -1; i++; }
      else if (i < s.length() && s.charAt(i) == '+') { i++; }
      while (i < s.length())
      {
         char ch = s.charAt(i);
         if ('0' <= ch && ch < '0' + base)
            r = r * base + ch - '0';
         else if ('A' <= ch && ch < 'A' + base - 10)
            r = r * base + ch - 'A' + 10 ;
         else if ('a' <= ch && ch < 'a' + base - 10)
            r = r * base + ch - 'a' + 10 ;
         else
            return r * sign;
         i++;
      }
      return r * sign;
   }

   /**
      Converts a string of digits to a <tt>double</tt>
      @param s a string
   */
   public static double atof(String s)
   {
      int i = 0;
      int sign = 1;
      double r = 0; // integer part
      double f = 0; // fractional part
      double p = 1; // exponent of fractional part
      int state = 0; // 0 = int part, 1 = frac part

      while (i < s.length() && Character.isWhitespace(s.charAt(i))) i++;
      if (i < s.length() && s.charAt(i) == '-') { sign = -1; i++; }
      else if (i < s.length() && s.charAt(i) == '+') { i++; }
      while (i < s.length())
      {
         char ch = s.charAt(i);
         if ('0' <= ch && ch <= '9')
         {
            if (state == 0)
               r = r * 10 + ch - '0';
            else if (state == 1)
            {
               p = p / 10;
               r = r + p * (ch - '0');
            }
         }
         else if (ch == '.')
         {
            if (state == 0) state = 1;
            else return sign * r;
         }
         else if (ch == 'e' || ch == 'E')
         {
            long e = (int)parseLong(s.substring(i + 1), 10);
            return sign * r * Math.pow(10, e);
         }
         else return sign * r;
         i++;
      }
      return sign * r;
   }

   /**
      Formats a <tt>double</tt> into a string (like sprintf in C)
      @param x the number to format
      @return the formatted string
      @exception IllegalArgumentException if bad argument
   */
   public String format(double x)
   {
      String r;
      if (precision < 0) precision = 6;
      int s = 1;
      if (x < 0) { x = -x; s = -1; }
      if (Double.isNaN(x)) r = "NaN";
      else if (x == Double.POSITIVE_INFINITY) r = "Inf";
      else if (fmt == 'f')
         r = fixedFormat(x);
      else if (fmt == 'e' || fmt == 'E' || fmt == 'g' || fmt == 'G')
         r = expFormat(x);
      else throw new java.lang.IllegalArgumentException();

      return pad(sign(s, r));
   }

   /**
      Formats an integer into a string (like sprintf in C)
      @param x the number to format
      @return the formatted string
   */
   public String format(int x)
   {
      long lx = x;
      if (fmt == 'o' || fmt == 'x' || fmt == 'X')
         lx &= 0xFFFFFFFFL;
      return format(lx);
   }

   /**
      Formats a long integer into a string (like sprintf in C)
      @param x the number to format
      @return the formatted string
   */
   public String format(long x)
   {
      String r;
      int s = 0;
      if (fmt == 'd' || fmt == 'i')
      {
         if (x < 0)
         {
            r = ("" + x).substring(1);
            s = -1;
         }
         else
         {
            r = "" + x;
            s = 1;
         }
      }
      else if (fmt == 'o')
         r = convert(x, 3, 7, "01234567");
      else if (fmt == 'x')
         r = convert(x, 4, 15, "0123456789abcdef");
      else if (fmt == 'X')
         r = convert(x, 4, 15, "0123456789ABCDEF");
      else throw new java.lang.IllegalArgumentException();

      return pad(sign(s, r));
   }

   /**
      Formats a character into a string (like sprintf in C)
      @param x the value to format
      @return the formatted string
   */
   public String format(char c)
   {
      if (fmt != 'c')
         throw new java.lang.IllegalArgumentException();

      String r = "" + c;
      return pad(r);
   }

   /**
      Formats a string into a larger string (like sprintf in C)
      @param x the value to format
      @return the formatted string
   */
   public String format(String s)
   {
      if (fmt != 's')
         throw new java.lang.IllegalArgumentException();
      if (precision >= 0 && precision < s.length())
         s = s.substring(0, precision);
      return pad(s);
   }


   /**
      a test stub for the format class
   */
   public static void main(String[] a)
   {
      double x = 1.23456789012;
      double y = 123;
      double z = 1.2345e30;
      double w = 1.02;
      double u = 1.234e-5;
      int d = 0xCAFE;
      Format.printf("x = |%f|\n", x);
      Format.printf("u = |%20f|\n", u);
      Format.printf("x = |% .5f|\n", x);
      Format.printf("w = |%20.5f|\n", w);
      Format.printf("x = |%020.5f|\n", x);
      Format.printf("x = |%+20.5f|\n", x);
      Format.printf("x = |%+020.5f|\n", x);
      Format.printf("x = |% 020.5f|\n", x);
      Format.printf("y = |%#+20.5f|\n", y);
      Format.printf("y = |%-+20.5f|\n", y);
      Format.printf("z = |%20.5f|\n", z);

      Format.printf("x = |%e|\n", x);
      Format.printf("u = |%20e|\n", u);
      Format.printf("x = |% .5e|\n", x);
      Format.printf("w = |%20.5e|\n", w);
      Format.printf("x = |%020.5e|\n", x);
      Format.printf("x = |%+20.5e|\n", x);
      Format.printf("x = |%+020.5e|\n", x);
      Format.printf("x = |% 020.5e|\n", x);
      Format.printf("y = |%#+20.5e|\n", y);
      Format.printf("y = |%-+20.5e|\n", y);

      Format.printf("x = |%g|\n", x);
      Format.printf("z = |%g|\n", z);
      Format.printf("w = |%g|\n", w);
      Format.printf("u = |%g|\n", u);
      Format.printf("y = |%.2g|\n", y);
      Format.printf("y = |%#.2g|\n", y);

      Format.printf("d = |%d|\n", d);
      Format.printf("d = |%20d|\n", d);
      Format.printf("d = |%020d|\n", d);
      Format.printf("d = |%+20d|\n", d);
      Format.printf("d = |% 020d|\n", d);
      Format.printf("d = |%-20d|\n", d);
      Format.printf("d = |%20.8d|\n", d);
      Format.printf("d = |%x|\n", d);
      Format.printf("d = |%20X|\n", d);
      Format.printf("d = |%#20x|\n", d);
      Format.printf("d = |%020X|\n", d);
      Format.printf("d = |%20.8x|\n", d);
      Format.printf("d = |%o|\n", d);
      Format.printf("d = |%020o|\n", d);
      Format.printf("d = |%#20o|\n", d);
      Format.printf("d = |%#020o|\n", d);
      Format.printf("d = |%20.12o|\n", d);

      Format.printf("s = |%-20s|\n", "Hello");
      Format.printf("s = |%-20c|\n", '!');

      // regression test to confirm fix of reported bugs

      Format.printf("|%i|\n", Long.MIN_VALUE);

      Format.printf("|%6.2e|\n", 0.0);
      Format.printf("|%6.2g|\n", 0.0);

      Format.printf("|%6.2f|\n", 9.99);
      Format.printf("|%6.2f|\n", 9.999);
      Format.printf("|%.2f|\n", 1.999);

      Format.printf("|%6.0f|\n", 9.999);
      Format.printf("|%20.10s|\n", "Hello");
      d = -1;
      Format.printf("-1 = |%X|\n", d);

      Format.printf("100 = |%e|\n", 100.0); // 2000-06-09
      Format.printf("1/0 = |%f|\n", 1.0 / 0.0);
      Format.printf("-1/0 = |%e|\n", -1.0 / 0.0);
      Format.printf("0/0 = |%g|\n", 0.0 / 0.0);
   }

   private static String repeat(char c, int n)
   {
      if (n <= 0) return "";
      StringBuffer s = new StringBuffer(n);
      for (int i = 0; i < n; i++) s.append(c);
      return s.toString();
   }

   private static String convert(long x, int n, int m, String d)
   {
      if (x == 0) return "0";
      String r = "";
      while (x != 0)
      {
         r = d.charAt((int)(x & m)) + r;
         x = x >>> n;
      }
      return r;
   }

   private String pad(String r)
   {
      String p = repeat(' ', width - r.length());
      if (leftAlign) return pre + r + p + post;
      else return pre + p + r + post;
   }

   private String sign(int s, String r)
   {
      String p = "";
      if (s < 0) p = "-";
      else if (s > 0)
      {
         if (showPlus) p = "+";
         else if (showSpace) p = " ";
      }
      else
      {
         if (fmt == 'o' && alternate && r.length() > 0 && r.charAt(0) != '0') p = "0";
         else if (fmt == 'x' && alternate) p = "0x";
         else if (fmt == 'X' && alternate) p = "0X";
      }
      int w = 0;
      if (leadingZeroes)
         w = width;
      else if ((fmt == 'd' || fmt == 'i' || fmt == 'x' || fmt == 'X' || fmt == 'o')
         && precision > 0) w = precision;

      return p + repeat('0', w - p.length() - r.length()) + r;
   }

   private String fixedFormat(double d)
   {
      boolean removeTrailing
         = (fmt == 'G' || fmt == 'g') && !alternate;
         // remove trailing zeroes and decimal point

      if (d > 0x7FFFFFFFFFFFFFFFL) return expFormat(d);
      if (precision == 0)
         return (long)(d + 0.5) + (removeTrailing ? "" : ".");

      long whole = (long)d;
      double fr = d - whole; // fractional part
      if (fr >= 1 || fr < 0) return expFormat(d);

      double factor = 1;
      String leadingZeroes = "";
      for (int i = 1; i <= precision && factor <= 0x7FFFFFFFFFFFFFFFL; i++)
      {
         factor *= 10;
         leadingZeroes = leadingZeroes + "0";
      }
      long l = (long) (factor * fr + 0.5);
      if (l >= factor) { l = 0; whole++; } // CSH 10-25-97

      String z = leadingZeroes + l;
      z = "." + z.substring(z.length() - precision, z.length());

      if (removeTrailing)
      {
         int t = z.length() - 1;
         while (t >= 0 && z.charAt(t) == '0') t--;
         if (t >= 0 && z.charAt(t) == '.') t--;
         z = z.substring(0, t + 1);
      }

      return whole + z;
   }

   private String expFormat(double d)
   {
      String f = "";
      int e = 0;
      double dd = d;
      double factor = 1;
      if (d != 0)
      {
         while (dd >= 10) { e++; factor /= 10; dd = dd / 10; } // 2000-06-09
         while (dd < 1) { e--; factor *= 10; dd = dd * 10; }
      }
      if ((fmt == 'g' || fmt == 'G') && e >= -4 && e < precision)
         return fixedFormat(d);

      d = d * factor;
      f = f + fixedFormat(d);

      if (fmt == 'e' || fmt == 'g')
         f = f + "e";
      else
         f = f + "E";

      String p = "000";
      if (e >= 0)
      {
         f = f + "+";
         p = p + e;
      }
      else
      {
         f = f + "-";
         p = p + (-e);
      }

      return f + p.substring(p.length() - 3, p.length());
   }

   private int width;
   private int precision;
   private String pre;
   private String post;
   private boolean leadingZeroes;
   private boolean showPlus;
   private boolean alternate;
   private boolean showSpace;
   private boolean leftAlign;
   private char fmt; // one of cdeEfgGiosxXos
}
最近下载更多
linmou  LV8 2023年3月19日
徐寿亮  LV1 2021年4月21日
xcj456  LV8 2020年9月12日
szy2503  LV2 2020年8月10日
moomin709  LV24 2020年2月19日
wsk588  LV26 2020年1月15日
ak130112  LV1 2019年12月31日
jizhaojian88  LV11 2019年8月20日
czh0510  LV12 2019年3月26日
罗颖钊  LV3 2018年12月6日
最近浏览更多
linmou  LV8 2023年3月19日
徐寿亮  LV1 2021年4月21日
高欢胜  LV1 2021年3月29日
2196316269  LV10 2021年2月24日
13043860zj  LV16 2020年9月24日
xcj456  LV8 2020年9月12日
szy2503  LV2 2020年8月10日
16692039904  LV2 2020年6月25日
fighter919  LV1 2020年5月6日
hb2008  LV3 2020年4月25日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友