java实现控制台打印表格【自动生成表格例程】
对于如下图的“学生成绩单”表格信息,如果用户有需求提取不同的字段列,只要传入报表参数和报表数据信息,本例程即可自动生成报表打印。
与C语言“汉字是双字节,ASCII码字符是单字节”不同;Java语言用双字节表示一个字符,无论是汉字还是ASCII码字符,Java字符串的长度单位也是双字节的。然而,通常情况,打印机的ASCII码字符只占一个字节长度,汉字则占两个字节长度。打印机的处理方式,与C语言是兼容的,但与Java语言不兼容。因此Java程序比C语言需要额外多做一些调整工作。
详细的程序代码如下:
public class AutoReport {
private char[][] lineSign = {
{'┏','━','┳','┓'},{'┃',' ','┃','┃'},
{'┣','━','╋','┫'},{'┗','━','┻','┛'}};
/*** hLines[]数组共有4个StringBuilder(64),分别用于保存:
* hLines[0] 表格头第一行表格线 "┏━━┳━━┓";
* hLines[1] 表格头第二行字段名称行"┃名称┃名称┃";
* hLines[2] 表格中间分隔行表格线 "┣━━╋━━┫";
* hLines[3] 表格最后一行表格线 "┗━━┻━━┛"; ***/
private StringBuilder[] hLines={null,null,null,null};
public AutoReport(ReportParam param,String[][]report)
{
mkReportHead(param); //生成报表头
prnReport(param,report); //打印报表
}
/***生成报表头的方法***/
private void mkReportHead( ReportParam param ) {
int len,k,fieldsNum;
String fldName;
int[] fields = param.fieldsSelected;
String[] fieldNames = param.fieldsName;
//初始化hLines[]
for (int i = 0; i < hLines.length; i++)
hLines[i] = new StringBuilder(64);
/*** 处理表头、表尾及字段名行和中间分隔线行***/
fieldsNum = param.fieldsSelected.length;//选定的字段个数
for (int i = 0; i < fieldsNum; i++)
{//switch语句"0:"处理首字段;"1:"处理中间字段,"default:"处理末字段。
if (i==0) k = 0; //每行第一个字段特殊处理。
else if (i==fieldsNum-1) k = 99; //末字段,特殊处理。
else k = 1; //中间字段处理方法都一样。
len = param.fieldsLen[i]; //第i个字段的长度
//定制指定长度的表头字段名字符串
fldName= getFixedLenString(fieldNames[(fields[i]-1)],len,'c');
switch (k) {
case 0: //每行首字段的处理
//追加制表符的每行行首字符,'┏'、'┃'、'┣'、'┗'
hLines[0].append(lineSign[0][0]); //表格头第一行
hLines[1].append(lineSign[1][0]); //表格字段名行
hLines[2].append(lineSign[2][0]); //表格中间分隔行
hLines[3].append(lineSign[3][0]); //表格最后一行
/*** 以上是每行的第一个字段特殊字符处理。***/
/*** 以下是各字段相同处理部分***/
for (int l = 0; l < len; l++) { //循环len次
hLines[0].append(lineSign[0][1]); //表格头第一行
hLines[2].append(lineSign[2][1]); //表格中间分隔行
hLines[3].append(lineSign[3][1]); //表格最后一行
}
//表格字段名行 hLines[1]:设置字段名称。与上面三行处理不同
hLines[1].append(fldName);
break;
case 1: //每行的中间字段的处理
//追加制表符的每个字段间制表符,如'┳'、'┃'、'╋'、'┻'等
hLines[0].append(lineSign[0][2]); //表格头第一行
hLines[1].append(lineSign[1][2]); //表格字段名称行
hLines[2].append(lineSign[2][2]); //表格中间分隔行
hLines[3].append(lineSign[3][2]); //表格最后一行
/*** 以下是各字段相同处理部分***/
for (int l = 0; l < len; l++) { //循环len次
hLines[0].append(lineSign[0][1]); //表格头第一行
hLines[2].append(lineSign[2][1]); //表格中间分隔行
hLines[3].append(lineSign[3][1]); //表格最后一行
}
//表格字段名行 hLines[1]:设置字段名称。与上面三行处理不同
hLines[1].append(fldName);
break;
default: //每行的最后一个字段的处理
//追加制表符的每个字段间制表符,如'┳'、'┃'、'╋'、'┻'等
hLines[0].append(lineSign[0][2]); //表格头第一行
hLines[1].append(lineSign[1][2]); //表格字段名称行
hLines[2].append(lineSign[2][2]); //表格中间分隔行
hLines[3].append(lineSign[3][2]); //表格最后一行
/*** 以下是各字段相同处理部分***/
for (int l = 0; l < len; l++) { //循环len次
hLines[0].append(lineSign[0][1]); //表格头第一行
hLines[2].append(lineSign[2][1]); //表格中间分隔行
hLines[3].append(lineSign[3][1]); //表格最后一行
}
//表格字段名行 hLines[1]:设置字段名称。与上面三行处理不同
hLines[1].append(fldName);
/*** 以上的处理是各字段相同处理部分***/
/*** 下面的处理是每行最后一个字段特殊处理。***/
//追加表格的行结束字符:'┓'、'┃'、'┫'、'┛'
hLines[0].append(lineSign[0][3]); //表格头第一行
hLines[1].append(lineSign[1][3]); //表格字段名行
hLines[2].append(lineSign[2][3]); //表格中间分隔行
hLines[3].append(lineSign[3][3]); //表格最后一行
break;
}
}
}
/***打印报表的方法***/
private void prnReport(ReportParam param,String[][]report) {
int len,fieldsNum;
char type;
String fixLenStr;
//打印表格表头
System.out.println(hLines[0].toString());
System.out.println(hLines[1].toString());
/***处理报表数据行***/
int[] fields = param.fieldsSelected;
fieldsNum = param.fieldsSelected.length;//选定的字段个数
StringBuilder dataLine = new StringBuilder(64);
//循环打印表格中间分隔行和数据行
for (int n = 0; n < report.length; n++) {
System.out.println(hLines[2].toString()); //打印表格中间分隔行
dataLine.delete(0, dataLine.capacity()); //清空dataLine数据
for (int i = 0; i < fieldsNum; i++) { //每行中的各个字段的处理
dataLine.append(lineSign[1][0]); //插入表格字符
//定制指定长度的字符串
len = param.fieldsLen[i]; //第i个字段的长度
type = param.fieldsType[i];//第i个字段的类型
fixLenStr = getFixedLenString(report[n][fields[i]-1],len,type);
dataLine.append(fixLenStr);
}
dataLine.append(lineSign[1][3]); //插入行尾表格字符
System.out.println(dataLine.toString());
}
//打印表格最后一行: 制表符表格封底线行。
System.out.println(hLines[3].toString());
}
/*** 定制指定长度的字符串方法
* @param str 字段信息;
* @param len 字段列指定的打印长度;
* @param type 数据类型。c左对齐;n右对齐;
* @return 指定长度的字符串。
* ***/
public String getFixedLenString(String str,int len, char type)
{
if (str==null||str.length()==0) str="";
int num = getASCIICharCount(str);//单字节字符数
/***计算需要补空格的长度***/
int k = 2*(len-str.length())+num;//需要补空格的长度
StringBuilder sBuilder = new StringBuilder(64);
/***字符串小于指定打印长度的,用空格(' ')作为填充字符***/
if (type=='c') { //左对齐,右补空格
sBuilder.append(str);
for (int i = 0; i < k; i++) sBuilder.append(' ');
}
else { //右对齐,左补空格
for (int i = 0; i < k; i++) sBuilder.append(' ');
sBuilder.append(str);
}
return sBuilder.toString();
}
/* 计算字符串中单字节字符出现的次数
* @param str
* @return
******/
public int getASCIICharCount(String str) {
if (str == null) { return 0; }
//非ASCII码字符的正则表达式
String reg = "[^\\x00-\\x7f]";
return str.replaceAll(reg, "").length();
}
public static void main(String[] args) {
int[] fieldsLen = {4,2,2,2,2,2,2,2};
char[] fieldsType = {'c','c','n','n','n','n','n','n'};
String[] fieldNames = {"姓名","学号","语文","数学","英语","物理","生物","历史"};
String[][] report = {
{"常昊","0801","88","100","68","85","80","65"},
{"刘国梁","0802","76","75","89","76","88","90"},
{"常遇春","0601","90","68","78","86","92","70"},
{"戚继光","0602","82","86","88","75","78","86"}};
//选定出报表的字段,用序号表示: 1 代表字段“姓名”,4代表字段“数学”,依次类推。
//选择前5个字段:"姓名","学号","语文","数学","英语"
int[] fields01 = {1,2,3,4,5};
int[] fields02 = {1,2,3,4,5,6,7,8}; //选择所有字段。
int[] fields03 = {1,2,3,4,6,8}; //随机选择字段。
//参数设定
ReportParam param = new ReportParam();
param.rowsInPage = 3; //重新设定每页行数
param.fieldsLen =fieldsLen;
param.fieldsType = fieldsType;
param.fieldsName = fieldNames;
param.fieldsSelected = fields01;
System.out.println(" 学 生 成 绩 单01");
new AutoReport(param, report);
param.fieldsSelected = fields02;
System.out.println(" 学 生 成 绩 单02");
new AutoReport(param, report);
param.fieldsSelected = fields03;
System.out.println(" 学 生 成 绩 单03");
new AutoReport(param, report);
}
}
class ReportParam { //报表参数
String[] fieldsName; //所有字段名称
//字段类型:c表示文本型;n表示数值型
char[] fieldsType; //所有字段的类型
int[] fieldsLen; //所有字段的长度
int[] fieldsSelected;//选定出报表的字段
//每页行数:可按需重新设定
int rowsInPage = 28; //每页行数默认值是28
}
程序未进行分页处理,有兴趣的可自行增加分页功能。程序的运行效果如下:(控制台的显示有点问题,对得不是很齐,这是把控制台显示结果复制到UltraEdit编辑器的效果图)