package io;
import java.util.GregorianCalendar;
import java.util.TimeZone;
/**
* Java 的格式化輸出
* Java 的格式化輸出一般用於下面幾種情況
* (1)String.format(String formatter,agr...)
* (2)System.out.printf(String formatter,agr...)
* (3)PrintWriter.printf(String formatter,agr...)
* 上面三種典型用法中,都是根據一個字符串格式的formatter和一個參數列表,獲得一個格式化的字符串.
* 其功能類似於c語言中的pringf函數.
* 參數formatter有固定的語法,主要語法有下面三種:
*
* (1)常規類型、字符類型和數值類型的格式說明符的語法如下:
*
* %[argument_index$][flags][width][.precision]conversion
*
* %: 這個是參數轉換格式化串的起點
* argument_index$: 由argument_index和$構成,表示使用後面參數列表中第argument_index參數來獲取格式化字符
* flags: 是一些標誌,比如 - 可以將參數左對齊,這個根據後面參數的具體類型有不同的標誌可選用
* width: 表示將後面參數格式化後的寬度,比如寬度爲3,並使用-作爲flag後,格式化整數5後,得到的字符串爲"5 ",即5後面加2空格
* .precision: 表示精度,這個一般針對浮點數,比如3.1415929 使用"%.2f"格式化之後得到3.14
* conversion:是格式化規則,比如上面的"%.2f"中的f就是一個規則,f只能對應浮點型參數,否則會拋異常
* conversion也是參數格式化串的終點
*
* 上面format(String formatter,agr...)中的formatter可以包含很多的參數格式化串,
* 也可以包含非格式化串,這些非格式化串字符將按照原樣輸出.
*
* 比如調用format("小明今年 %2$-3d歲,生於 %1$-5d年.",1994,20)
* 得到的格式化之後的字符串爲:小明今年 20 歲,生於 1994 年.
* 注意,上面的formatter中包含兩個格式化串:%2$-3d 和 %1$-5d,都是以%開頭,d(conversion)結尾的.
* 其他部分,是非格式化串字符,比如"小明今年 "則按原樣輸出.
* %2$-3d中的2$表示使用後面的第二個參數,也就是20.注意這裏20是2個寬度,而-3表示格式化成3個寬度並且左對齊,
* 這樣得到的輸出就是"20 歲",20和歲之間加了一個空格,以是的20格式化之後的寬度變成3.
*
* (2)用來表示日期和時間類型的格式說明符的語法如下:
*
* %[argument_index$][flags][width]conversion
*
* 這個跟上面的有兩點區別:首先,格式化時間不需要[.precision]這個了;
* 其次,格式化時間的conversion 有特殊要求,即,必須要在前面加一個t或T.
* 有一些專門的conversion用於格式化時間,使用這些conversion時,需要在前面加一個t
*
* 比如,
* Calendar c = new GregorianCalendar(1984, 6, 4);
* String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
* 這裏%1$tm中的m是conversion,表示輸出兩位數月份,t是前綴.
* 格式化之後得到:Duke's Birthday: 07 4,1984
*
* (3)與參數不對應的格式說明符的語法如下:
*
* %[flags][width]conversion
*
* 這個與前面(1)的區別是去掉了[argument_index$]和[.precision]表示:
* 首先,不能指定參數位置與格式化串的對應關係,則使用格式化串的位置尋找後面對應位置的參數
* format("小明今年 %-3d歲,生於 %-5d年.",1994,20)
* 上面的格式化串%-3d位置爲1,則使用第一個參數1994來獲取格式化串,
* 最終返回"小明今年 1994歲,生於 20 年." 這樣就不對了.
* 所以,後面的參數位置要和前面的格式化串對應.改成:
* format("小明今年 %-3d歲,生於 %-5d年.",20,1994)
*
*
*/
public class TestStringFormat
{
public static void main(String[] args)
{
//格式化輸出整數
String str1 = String.format("小明今年 %2$-3d歲,生於 %1$-5d年.",1994,20);
System.out.println(str1);
//輸出:小明今年 20 歲,生於 1994 年.
//沒有參數對應時,要讓格式化串和參數的順序對應好
str1 = String.format("小明今年 %-3d歲,生於 %-5d年.",20,1994,20);
System.out.println(str1);
//輸出:小明今年 20 歲,生於 1994 年.
//沒有參數對應時,參數數量少於格式化串數量時,格式化串變成空,
//參數多了則沒關係(參考上面的20,1994,20三個參數只用到了兩個)
//有參數對應時,如果用3$指定了第三個參數,而參數列表中只有2個參數則會報錯
//str1 = String.format("小明今年 %2$-3d歲,生於 %1$-5d年.",1994);//這樣的報錯
//格式化日期,時間
GregorianCalendar c = new GregorianCalendar(1984, 6, 4,12,22,33);//構造制定日期時間的日曆
c.setTimeZone(TimeZone.getTimeZone("GMT+8"));
c.setTimeInMillis(System.currentTimeMillis());//設置爲當前日期時間
str1 = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
System.out.println(str1);//輸出:Duke's Birthday: 02 27,2014
str1 = String.format("Time: %1$tH:%1$tM:%1$tS",c);
System.out.println(str1);//輸出: Time: 20:19:09
//格式化浮點數,如果浮點數格式化後小數位數小於原來的值,則是按照四捨五入方式 捨棄的
str1 = String.format("π值爲 %1$s,浮點數爲:%1$f,精確到3位小數爲:%1$.3f", 3.1415926);
System.out.println(str1);//輸出:π值爲 3.1415926,浮點數爲:3.141593,精確到3位小數爲:3.142
//格式化輸出數組,左對齊,每個整數佔5個寬度
int[][] dataArr = {{1,2,3},{4,5,6}};
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
System.out.printf("%-5d",dataArr[i][j]);
}
System.out.println("");
}
/*
* 輸出:
* 1 2 3
* 4 5 6
*/
}
}