Topic: 请大家推荐好的字符串格式化方法? |
Print this page |
1.请大家推荐好的字符串格式化方法? | Copy to clipboard |
Posted by: spi_cn Posted on: 2004-08-03 10:11 类似于C/C++中的printf,谢谢! |
2.Re:请大家推荐好的字符串格式化方法? [Re: spi_cn] | Copy to clipboard |
Posted by: xiongjy Posted on: 2004-08-04 14:16 jdk1.5支持 |
3.Re:请大家推荐好的字符串格式化方法? [Re: spi_cn] | Copy to clipboard |
Posted by: yung Posted on: 2004-08-09 20:29 package com; /* * File........: Str.java * Package.....: gk.util * Created.....: 97/12/17, Guido Krueger * RCS.........: $Revision: 1.2 $ * $Date: 1999/03/18 21:12:08 $ $Author: guido $ * * Copyright 1997 Guido Krueger. All Rights Reserved. * * Permission to use, copy, modify, and distribute this * software and its documentation for NON-COMMERCIAL purposes * and without fee is hereby granted provided that this * copyright notice appears in all copies. * * THE AUTHOR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR * NON-INFRINGEMENT. THE AUTHOR SHALL NOT BE LIABLE FOR ANY * DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ /** * This class provides a number of supporting String methods which are * otherwise not found in the java.util package. They are * implemented as static methods which take a String as argument and/or * provide a String as return value. This class can be divided into the * following sections: * <ul> * <li>General String and String manipulation methods. * <ul> * <li>getSpaces() returns an empty String * <li>getZeros() returns a zero-filled String * <li>padLeft() left-pads a String to a given width * <li>padRight() right-pads a String to a given width * <li>padZero() left-pads a String with zeros * </ul> * <li>Formatted output of primitive data types (like printf in C/C++). * <ul> * <li>getFormatted() takes a String and a value argument and returns * a composed String according to the printf formatting rules. * This method is available for values of type int, double, char * and String. * </ul> * </ul> * <p> * getFormatted mostly follows the conventions used in C/C++ printf * formatting, thoufg there are some slight differences. If you're not * familar with printf, you may consider to take a look in any good * C reference. Here are the rules for out format String: * <ul> * <li>There may be an arbibtrary number of format specifiers. * Only the first one is used to obtain the format information. * <li>The format specifier must have the form: * <pre> * %[-][+][0-9][.0-9][lL][dxXuofeEgGcs] * || | | | | | * || | | | | +- format char, see below * || | | | +----- long modifier, ignored * || | | +----------- decimals * || | +---------------- field length * || +------------------- plus sign * |+---------------------- leftalign * +----------------------- percent sign, starts format specifier * </pre> * <ul> * <li>The percent sign always starts the format specifiert. Two * consecutive %'s could be used to literally generate a single % * <li>A "-" aligns output left (usually, it's right-aligned). * <li>A "+" outputs a plus sign for positive numbers (usually, it is * supressed. * <li>The field length specifies the overall field length. If the * formatted value is shorter, it will be padded with blanks, * if it longer, it will remain unchanged. * <li>The number of decimals specifies the length of the fractional * part for floating point numbers. If ommitted, the default is 6. * </ul> * The format char determines the base type for the formatted value * and has a big impact on how the result appears: * <ul> * <li>"d": integer value in decimal format. * <li>"x": integer value in hexadecimal format (letters in lowercase). * <li>"X": integer value in hexadecimal format (letters in uppercase). * <li>"u": absolute integer value in decimal format. Result will always * be positive. * <li>"o": integer value in octal format. * <li>"f": floating point value in fixed format (xxx.yyyyyy). * <li>"e": floating point value in scientific format (0.yyyyyye+zzz). * <li>"E": floating point value in scientific format (0.yyyyyyE+zzz). * <li>"g": same as "f" for absolute values not smaller than 0.001 and * not greater or equal than 1000. Otherwise, same as "e". * <li>"G": same as "f" for absolute values not smaller than 0.001 and * not greater or equal than 1000. Otherwise, same as "E". * <li>"c": single character. * <li>"s": String. * </ul> * Here are some additional hints: * <ul> * <li>For the "e" and "E" format chars the following is true: * <ul> * <li>The mantissa is normalized to its canonical form, i.e. it's * always smaller than 1.0 and greater than or equal to 0.1 * <li>The exponent has always three digits. * <li>The exponent always shows a sign, even for positive values. * <li>The length of the frational part is subject to the number * of decimals specified in the format string. If omitted, it * defaults to 6. * </ul> * <li>The fractional part is subject to rounding for the last visible * digit. Overflows could be propagated into the integer part or * even into the exponent. * <li>The "u" format char behaves different as in C/C++. Here, it always * displays the absolute value of the argument in decimal format. * <li>The "l" and "L" modfiers are completely ignored. * <li>The number of decimals is applied to all format chars except "c" * and "s". For integer values, the fractional part is always 0. * </ul> * </ul> * * @version 1.0, 97/12/25 * @author Guido Krueger */ public class Fmt { //---Constants------------------------------------------------------- static final int MAXSPACES = 2560; static final int MAXZEROS = 2560; static final int DEFAULTDECIMALS = 6; static final int EXPONENTLEN = 3; //---Pseudo Constants------------------------------------------------ static String SPACES = " "; static int SPACESLEN = 40; static String ZEROS = "0000000000000000000000000000000000000000"; static int ZEROSLEN = 40; static Object lock = new Object(); //---Public general String handling methods-------------------------- /** * Returns an empty String (i.e. a String which consists of only blanks) * of the specified length. * * @param len length of String to return. * @return Blank String of the given length. * @exception StringIndexOutOfBoundsException if len is larger than * MAXSPACES (currently 2560). */ static public String getSpaces(int len) { if (len > SPACESLEN && SPACESLEN < MAXSPACES) { //aquire lock only when neccessary synchronized (lock) { while (len > SPACESLEN && SPACESLEN < MAXSPACES) { SPACES += SPACES; SPACESLEN += SPACESLEN; } } } return SPACES.substring(0, len); } /** * Returns a String of the specified length which consists of only * Zeros (ASCII 48). * * @param len length of String to return. * @return Zero-filled String of the given length. * @exception StringIndexOutOfBoundsException if len is larger than * MAXZEROS (currently 2560). */ static public String getZeros(int len) { if (len > ZEROSLEN && ZEROSLEN < MAXZEROS) { //aquire lock only when neccessary synchronized (lock) { while (len > ZEROSLEN && ZEROSLEN < MAXZEROS) { ZEROS += ZEROS; ZEROSLEN += ZEROSLEN; } } } return ZEROS.substring(0, len); } /** * Pads the String s to the given length by inserting blanks at the left * side. If s is longer than len, the String remains unchanged. * * @param s String to pad * @param len length of resulting String * @return The padded String. */ static public String padLeft(String s, int len) { return padLeft(s, len, false); } /** * Pads the String s to the given length by inserting blanks at the left * side. If s is longer than len and trim is set to true, the result is * truncated to the given length. * * @param s String to pad * @param len length of resulting String * @param trim truncates s if longer then len * @return The padded String. */ static public String padLeft(String s, int len, boolean trim) { int slen = s.getBytes().length; String ret; if (slen < len) { ret = getSpaces(len - slen) + s; } else if (slen > len && trim) { ret = s.substring(0, len); } else { ret = s; } return ret; } /** * Pads the String s to the given length by inserting blanks at the right * end. If s is longer than len, the String remains unchanged. * * @param s String to pad * @param len length of resulting String * @return The padded String. */ static public String padRight(String s, int len) { return padRight(s, len, false); } /** * Pads the String s to the given length by inserting blanks at the right * end. If s is longer than len and trim is true, the result is * truncated to the given length. * * @param s String to pad * @param len length of resulting String * @param trim truncates s if longer then len * @return The padded String. */ static public String padRight(String s, int len, boolean trim) { int slen = s.getBytes().length; String ret; if (slen < len) { ret = s + getSpaces(len - slen); } else if (slen > len && trim) { ret = s.substring(0, len); } else { ret = s; } return ret; } /** * Left-pads the String with zeros to the given length. * * @param s String to pad * @param len length of resulting String * @return The padded value as a String. */ static public String padZero(String s, int len) { int slen = s.length(); String ret; if (slen < len) { ret = getZeros(len - slen) + s; } else { ret = s; } return ret; } /** * Converts the integer value into a String which is left-padded with * zeros to the given length. * * @param value integer value to pad * @param len length of resulting String * @return The padded value as a String. */ static public String padZero(int value, int len) { String s = "" + value; int slen = s.length(); String ret; if (slen < len) { ret = getZeros(len - slen) + s; } else { ret = s; } return ret; } //---Public String formatting methods-------------------------------- /** * Formats the value according to the given format specifier. The * format char may be any character out of "dxXoufeEgGc". If the * format char is in "feEgG", the value is casted to a double, if * it is "c", it is casted to a char, before actually calling the * corresponding formatting method. * * @param format format specifier according to the rules * mentioned above * @param value integer value which should be formatted as * specified in the format argument * @return The formatted value as a String. If the format char * is "s", the return value is the error * message "<***cannot convert value***>". */ public static String getFormatted(String format, int value) { String ret; FormatParas fp = new FormatParas(); parseFormatString(format, fp); ret = fp.prefix.toString(); if (fp.specfound) { String valstring; if (fp.basetype == 'i') { valstring = toString(value, fp); } else if (fp.basetype == 'f') { valstring = toString((double)value, fp); } else if (fp.basetype == 'c') { valstring = toString((char)value, fp); } else { valstring = "<***cannot convert value***>"; } ret += valstring + fp.suffix.toString(); } return ret; } /** * Formats the value according to the given format specifier. The * format char may be any character out of "dxXoufeEgG". If the * format char is in "dxXou", the value is casted to an int before * actually calling the corresponding formatting method. * * @param format format specifier according to the rules * mentioned above * @param value double value which should be formatted as * specified in the format argument * @return The formatted value as a String. If the format char * is "c" or "s", the return value is the error * message "<***cannot convert value***>". */ public static String getFormatted(String format, double value) { String ret; FormatParas fp = new FormatParas(); parseFormatString(format, fp); ret = fp.prefix.toString(); if (fp.specfound) { String valstring; if (fp.basetype == 'f') { valstring = toString(value, fp); } else if (fp.basetype == 'i') { valstring = toString((int)value, fp); } else { valstring = "<***cannot convert value***>"; } ret += valstring + fp.suffix.toString(); } return ret; } /** * Formats the value according to the given format specifier. The * format char may be any character out of "csdxXou". If the * format char is "s", the value is considered a String of length 1. * If it is in "dxXou", the value is casted to an int before * actually calling the corresponding formatting method. * * @param format format specifier according to the rules * mentioned above * @param value character which should be formatted as * specified in the format argument * @return The formatted value as a String. If the format char * is in "feEgG", the return value is the error * message "<***cannot convert value***>". */ public static String getFormatted(String format, char value) { String ret; FormatParas fp = new FormatParas(); parseFormatString(format, fp); ret = fp.prefix.toString(); if (fp.specfound) { String valstring; if (fp.basetype == 'c') { valstring = toString(value, fp); } else if (fp.basetype == 's') { valstring = toString("" + value, fp); } else if (fp.basetype == 'i') { valstring = toString((int)value, fp); } else { valstring = "<***cannot convert value***>"; } ret += valstring + fp.suffix.toString(); } return ret; } /** * Formats the value according to the given format specifier. The * format char has to be the character "s". * * @param format format specifier according to the rules * mentioned above * @param value String value which should be formatted as * specified in the format argument * @return The formatted value as a String. If the format char * is different from "s", the return value is the error * message "<***cannot convert value***>". */ public static String getFormatted(String format, String value) { String ret; FormatParas fp = new FormatParas(); parseFormatString(format, fp); ret = fp.prefix.toString(); if (fp.specfound) { String valstring; if (fp.basetype == 's') { valstring = toString(value, fp); } else { valstring = "<***cannot convert value***>"; } ret += valstring + fp.suffix.toString(); } return ret; } /** * This method could be used to run the format parser on the first * argument and then return the format specification as a String. * It is thought for debugging purposes and need not be called * under normal circumstances. It's declared public because the * test engine is in a different package and thus can not call * package level methods. * * @param format format specifier according to the rules * mentioned above * @return The parsed format String in a human-readable format. */ public static String testFormatParser(String format) { FormatParas fp = new FormatParas(); parseFormatString(format, fp); return "\nFormat String....: " + format + "\n" + fp.toString(); } //---Private methods------------------------------------------------- /** * Converts the integer value into a String according to the format * encoded in fp. This method supports the format specifiers * "d", "u", "x" and "o". It interprets the modifiers "alignleft", * "plussign", "fieldlen", "padzero" and "decimals". */ private static String toString(int value, FormatParas fp) { String ret = ""; int signlen = 0; char sign = ' '; //Value conversion if (fp.convchar == 'd' || fp.convchar == 'u') { if (fp.convchar == 'u') { value = Math.abs(value); } if (value < 0) { ret = "" + (-value); signlen = 1; sign = '-'; } else { ret = "" + value; if (fp.plussign) { signlen = 1; sign = '+'; } } if (fp.decimals > 0) { ret += "." + getZeros(fp.decimals); } } else if (fp.convchar == 'x') { ret = Integer.toHexString(value); } else if (fp.convchar == 'X') { ret = Integer.toHexString(value).toUpperCase(); } else if (fp.convchar == 'o') { ret = Integer.toOctalString(value); } //Padding if (fp.fieldlen > 0) { if (fp.padzero) { ret = padZero(ret, fp.fieldlen - signlen); if (signlen > 0) { ret = sign + ret; } } else { if (signlen > 0) { ret = sign + ret; } if (fp.alignleft) { ret = padRight(ret, fp.fieldlen); } else { ret = padLeft(ret, fp.fieldlen); } } } else if (signlen > 0) { ret = sign + ret; } return ret; } /** * Converts the double value into a String according to the format * encoded in fp. This method supports the format specifiers * "f", "e", "E", "g" nd "G". It interprets the modifiers "alignleft", * "plussign", "fieldlen", "padzero" and "decimals". * * The floating point formatter always transforms the value into * the normalized canonical form "0.xy" where the whole part * is 0 and the first digit x of the fractional part is not 0. The * implementation relies on the fact that the implicit Java String * conversion for normalized values always returns a String in the * format mentioned above. */ private static String toString(double value, FormatParas fp) { String ret = ""; char convchar = fp.convchar; //Sign int signlen = 0; char sign = ' '; if (value < 0) { signlen = 1; sign = '-'; value = -value; } else { if (fp.plussign) { signlen = 1; sign = '+'; } } //Modify convchar if (fp.convchar == 'g' || fp.convchar == 'G') { if (value >= 1000.0 || value < 0.001) { convchar = (fp.convchar == 'g') ? 'e' : 'E'; } else { convchar = 'f'; } } //Compute exponent and canonical form int exp; String canonical; if (value == 0.0) { exp = 0; canonical = "0.0"; } else { exp = (int)(Math.floor(Math.log(value) / Math.log(10)) + 1); //Checking for possible floating value representation errors //Occure if value is a multiple of 1000 double normalized = value / Math.pow(10.0, exp); if (normalized >= 1.0) { //exp too small, multiplied by 10 exp += 1.0; normalized = value / Math.pow(10.0, exp); } if (normalized < 0.1) { //exp too big, divided by 10 exp -= 1.0; normalized = value / Math.pow(10.0, exp); } //Creating canonical form canonical = "" + normalized; } if (!canonical.startsWith("0.")) { ret = "***unexpected canonical form: " + ret; } else { //Value conversion canonical = canonical.substring(2); String s1, s2, s3; if (convchar == 'f') { if (exp > 0) { s1 = (canonical + getZeros(exp)).substring(0, exp); s2 = (canonical + getZeros(exp)).substring(exp); } else if (exp < 0) { s1 = "0"; s2 = getZeros(-exp) + canonical; } else { s1 = "0"; s2 = canonical; } s3 = ""; } else { //convchar is 'e' or 'E' s1 = "0"; s2 = canonical; if (exp >= 0) { s3 = "" + convchar + "+" + padZero(exp, EXPONENTLEN); } else { s3 = "" + convchar + "-" + padZero(-exp, EXPONENTLEN); } } //Correcting number of decimals and rounding int decimals = (fp.decimals == -1) ? DEFAULTDECIMALS : fp.decimals; if (decimals == 0) { if (s2.charAt(0) >= '5') { s1 = incrementString(s1); } s2 = ""; } else { s2 += getZeros(decimals + 1); if (s2.charAt(decimals) >= '5') { s2 = incrementString(s2.substring(0, decimals)); if (s2.length() > decimals) { //overflow in fractional part if (convchar == 'f') { //set frac part to zero and propagate overflow to integer part s2 = s2.substring(1); s1 = incrementString(s1); } else { //normalize frac part and propagate overflow to exponent s2 = "1" + s2.substring(2); int newexp = exp + 1; if (newexp >= 0) { s3 = "" + convchar + "+" + padZero(newexp, EXPONENTLEN); } else { s3 = "" + convchar + "-" + padZero(-newexp, EXPONENTLEN); } } } } else { s2 = s2.substring(0, decimals); } } //Building raw version ret = s1 + (decimals > 0 ? ("." + s2) : "") + s3; //Padding if (fp.fieldlen > 0) { if (fp.padzero) { ret = padZero(ret, fp.fieldlen - signlen); if (signlen > 0) { ret = sign + ret; } } else { if (signlen > 0) { ret = sign + ret; } if (fp.alignleft) { ret = padRight(ret, fp.fieldlen); } else { ret = padLeft(ret, fp.fieldlen); } } } else if (signlen > 0) { ret = sign + ret; } } return ret; } /** * Converts the char value into a String according to the format * encoded in fp. This method supports the format specifier "c" with * the "fieldlen" and "alignleft" modifiers. */ private static String toString(char value, FormatParas fp) { String ret = "" + value; if (fp.fieldlen > 0) { if (fp.alignleft) { ret = padRight(ret, fp.fieldlen); } else { ret = padLeft(ret, fp.fieldlen); } } return ret; } /** * Formats the String value according to the format encoded in fp. This * method supports the format specifier "s" with the "fieldlen" and * "alignleft" modifiers. */ private static String toString(String value, FormatParas fp) { if (fp.fieldlen > 0) { if (fp.alignleft) { value = padRight(value, fp.fieldlen); } else { value = padLeft(value, fp.fieldlen); } } return value; } /** * This method is used to parse the format String and to split it up * into three parts: * <ol> * <li>All characters which occur before the first format specifier * will be stored in the "prefix" component. * <li>All characters which occur after the end of the first format * specifier will be stored in the "suffix" component. * <li>All charactcers which comprise the first format specifiert are * scanned and stored in a structured way. * </ol> * All three parts are returned in the fp argument which is described * in more detail below. */ private static void parseFormatString(String format, FormatParas fp) { int specpos = 0; int formatlen = format.length(); while (formatlen > 0) { specpos = format.indexOf("%"); if (specpos == -1 || specpos >= formatlen - 1) { //% not found or last char in format if (!fp.specfound) { fp.prefix.append(format); } else { fp.suffix.append(format); } format = ""; formatlen = 0; } else if (format.charAt(specpos + 1) == '%') { //found two consecutive %'s if (!fp.specfound) { fp.prefix.append(format.substring(0, specpos + 1)); } else { fp.suffix.append(format.substring(0, specpos + 1)); } format = format.substring(specpos + 2); formatlen -= (specpos + 2); } else if (fp.specfound) { //found single % in suffix fp.suffix.append(format.substring(0, specpos + 1)); format = format.substring(specpos + 1); formatlen -= (specpos + 1); } else { //found first single % fp.prefix.append(format.substring(0, specpos)); format = format.substring(specpos + 1); formatlen -= (specpos + 1); fp.specfound = true; //now scanning format specifier for -+lL0123456789.dxXoufeEgGcs chars int i = 0, numpos = 0; int num[] = {-1, -1}; boolean firstdigit = true; while (i < formatlen) { char c = format.charAt; if (c == '-') { fp.alignleft = true; } else if (c == '+') { fp.plussign = true; } else if (c == 'l' || c == 'L') { fp.aslong = true; } else if (c >= '0' && c <= '9') { if (num[numpos] == -1) { num[numpos] = 0; } num[numpos] = 10 * num[numpos] + c - '0'; if (c == '0' && firstdigit) { fp.padzero = true; } firstdigit = false; } else if (c == '.') { numpos = 1; } else if ("dxXou".indexOf != -1) { fp.convchar = c; fp.basetype = 'i'; ++i; break; } else if ("feEgG".indexOf != -1) { fp.convchar = c; fp.basetype = 'f'; ++i; break; } else if (c == 'c') { fp.convchar = c; fp.basetype = 'c'; ++i; break; } else if (c == 's') { fp.convchar = c; fp.basetype = 's'; ++i; break; } else { ++i; break; } ++i; } fp.fieldlen = num[0]; fp.decimals = num[1]; //specifier completely scanned format = format.substring; formatlen -= i; } } } /** * Treats the String as character-encoded positive integer value and * increments it by 1. The return value is larger than s if and only * if s completely consisted of "9" digits. This case could be * considered an overflow. */ private static String incrementString(String s) { int i; StringBuffer sb = new StringBuffer; for (i = sb.length() - 1; i >= 0; --i) { char c = sb.charAt; if (c < '9') { sb.setCharAt(i, (char)(c + 1)); break; } else { sb.setCharAt(i, '0'); } } return ((i == -1) ? "1" : "") + sb.toString(); } } /** * This class is used to hold the properties of a single format specifier. * It is filled by the parseFormatString method and is used by several * other methods. * * @version 1.0, 97/12/21 * @author Guido Krueger */ class FormatParas { boolean specfound; //A valid format specifier was found int fieldlen; //Length of field (-1 if not specified) int decimals; //Number of decimals (-1 if not specified) boolean alignleft; //Left align inside output field boolean padzero; //Pad with leading zeros boolean plussign; //Output plus sign for positive numbers boolean aslong; //"long" modifier found char convchar; //Conversion character char basetype; //i=integer f=floatingpoint s=String c=char StringBuffer prefix; //Substring on the left of the specifier StringBuffer suffix; //Substring on the right of the specifier /** * Initializes all members to their default values. */ public FormatParas() { specfound = false; fieldlen = -1; decimals = -1; alignleft = false; padzero = false; plussign = false; aslong = false; convchar = ' '; prefix = new StringBuffer(""); suffix = new StringBuffer(""); } /** * Returns a String representation of the object's state. */ public String toString() { String ret = ""; ret += "specfound........: " + specfound + "\n"; ret += "fieldlen.........: " + fieldlen + "\n"; ret += "decimals.........: " + decimals + "\n"; ret += "alignleft........: " + alignleft + "\n"; ret += "padzero..........: " + padzero + "\n"; ret += "plussign.........: " + plussign + "\n"; ret += "aslong...........: " + aslong + "\n"; ret += "convchar.........: " + convchar + "\n"; ret += "prefix...........: " + prefix + "\n"; ret += "suffix...........: " + suffix + "\n"; return ret; } } |
4.Re:请大家推荐好的字符串格式化方法? [Re: spi_cn] | Copy to clipboard |
Posted by: xuyang821225 Posted on: 2004-08-10 11:41 真的很能写啊~~~佩服! |
Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1 客服电话 18559299278 客服信箱 714923@qq.com 客服QQ 714923 |