/*
プログラミングのお題スレ Part13
https://m...content-available-to-author-only...h.net/test/read.cgi/tech/1549160513/
831デフォルトの名無しさん2019/04/24(水) 20:52:14.50ID:NALZs80Z
お題: 簡易なテーブルを綺麗に整形する
余力があればカラムの左揃え、右揃えをオプションで選択できるようにする(出力は中央揃え)
入力:
a|aaaaa|bb
ccc|ddd|ee
出力:
**a***|*aaaaa*|***bb*
------+-------+------
*ccc**|**ddd**|***ee*
*/
#include <stdio.h>
#include <stdlib.h>
/* セル内の壁と文字列の間のスペース文字数 */
#define RDD_CHAR (' ')
#define RDD_CHAR_NUM 1
/* セル内の文字列が終わったときに使う、空の文字列 */
#define SPACE_CHAR ('*')
/* 配列で取得する最大サイズ */
typedef enum{
in_max_row = 16,
in_max_col = 1024,
table_max_row = 16,
table_max_col = 16,
out_max_row = in_max_row * 2 + 1, //input_max_row に依存
out_max_col = 2048
}max_size;
typedef struct{
char *ptr;
int size;
}tablestr_t;
/* 動作モード */
enum str_pos_id{
/* セル中の文字列の位置 */
LEFT, //左寄せ
MEDIUM, //中間
RIGHT //右寄せ
};
enum cell_width_id{
/* セルの幅 */
MAX_IN_TABLE, //すべてのセルを表の最大幅のセルに合わせる
MAX_IN_EACH_COL //各列のセルをその列の最大幅に合わせる
};
int tbl(char output[out_max_row][out_max_col],
char input[in_max_row][in_max_col],
enum str_pos_id mode_str_pos,
enum cell_width_id mode_cell_width){
/* セル内の壁と文字列の間のスペース文字数 */
int rdd_char_num = RDD_CHAR_NUM; //redundant space , 0以上の整数
char rdd_char = RDD_CHAR;
/* セル内の文字列が終わったときに使う、空の文字列 */
char space_char = SPACE_CHAR;
/* カウンタ */
int i, j;
/* セルの内容を記録する配列 */
tablestr_t table[table_max_row][table_max_col];
/* 表の区切りの水平線の文字列配列 */
char table_hori_line[out_max_col];
/* 各列のセルの幅を記録する配列 */
int col_cell_width[table_max_col];
/* 表の最も大きいセルの幅 */
int cell_max_width;
/* 各配列の行と列のサイズ */
int in_row, in_col;
int table_row, table_col;
int out_row, out_col;
/* 配列初期化 */
//table
for(i = 0; i < table_max_row; i++){
for(j = 0; j < table_max_col; j++){
table[i][j].ptr = NULL;
table[i][j].size = 0;
}
}
//col_cell_width
for(i = 0; i < table_max_col; i++){
col_cell_width[i] = 0;
}
//output
for(i = 0; i < out_max_row; i++){
for(j = 0; j < out_max_col; j++){
output[i][j] = '\0';
}
}
//table_hori_line
for(i = 0; i < in_max_col; i++){
table_hori_line[i] = '\0';
}
/* in_row, in_colを計算 */
for(i = 0; i < in_max_row; i++){
/* その行の最初の文字がnull文字なら、そこでデータの終点とする */
if(input[i][0] == '\0'){
in_row = i;
break;
}
}
/* in_col はin_max_colに設定 */
in_col = in_max_col;
/* table_row, table_colを計算 */
/* table_row がtable_max_rowに収まるサイズか確認 */
table_row = in_row;
if(table_row > table_max_row){
puts("ERROR: table_row > table_max_row"); return(1);
}
/* 各行のセルの数をカウントする */
//最終的に最大のセル数に合わせる
{ //一時変数隠蔽用ブロック
int temp;
char crr_char;
char prev_char;
table_col = 0;
for(i = 0; i < in_row; i++){
temp = 0;
prev_char = '\0';
for(j = 0; (j < in_col) && ( (crr_char = input[i][j]) != '\0'); j++){
if(crr_char == '|'){
temp++;
}
prev_char = crr_char;
}
if(prev_char != '|'){
temp++;
}
if(table_col < temp){
table_col = temp;
}
}
}
if(table_col > table_max_col){
puts("ERROR: table_col > table_max_col"); return(1);
}
/* tablelist の各セルに inputのポインタを登録 */
{ //一時変数隠蔽用ブロック
char *ptr; //inputの文字列開始位置
int size; //文字列数
int in_crr_col; //inputの文字列の解析位置
char crr_char;
for(i = 0; i < table_row; i++){
in_crr_col = 0;
for(j = 0; j < table_col; j++){
ptr = &input[i][in_crr_col];
size = 0;
while( ( (crr_char = input[i][in_crr_col]) != '|' ) && (crr_char != '\0') ){
in_crr_col++;
size++;
}
table[i][j].ptr = ptr;
table[i][j].size = size;
if(crr_char == '|'){
in_crr_col++;
}
else if(crr_char == '\0'){
break;
}
}
}
}
/* col_cell_width を計算 */
{
int temp = 0;
int cell_crr_col;
for(i = 0; i < in_row; i++){
cell_crr_col = 0;
temp = 0;
for(j = 0; j < in_col; j++){
/* '|'かnull文字を検索し、セルの最大幅を求める */
/* '|'だったら、tempを比較しリセット */
if(input[i][j] == '|'){
if(col_cell_width[cell_crr_col] < temp){
col_cell_width[cell_crr_col] = temp;
}
temp = 0;
cell_crr_col++;
}
/* null文字だったら、tempを比較しリセット、 ループ終了。次の行へ */
else if(input[i][j] == '\0'){
if(col_cell_width[cell_crr_col] < temp){
col_cell_width[cell_crr_col] = temp;
}
break;
}
/* どちらでもないなら +1 */
else{
temp++;
}
}
}
/* cell_max_widthを計算 */
cell_max_width = col_cell_width[0];
for(i = 1; i < table_col; i++){
if(cell_max_width < col_cell_width[i]){
cell_max_width = col_cell_width[i];
}
}
switch(mode_cell_width){
case MAX_IN_TABLE:
for(i = 0; i < table_col; i++){
col_cell_width[i] = cell_max_width;
}
break;
case MAX_IN_EACH_COL:
//特に何もしない
break;
default:
puts("'mode_cell_width' has invalid value"); return(1);
break;
}
}
/* out_row, out_col を計算 */
out_row = table_row * 2 + 1;
if(out_row > out_max_row){
puts("ERROR: out_row > out_max_row"); return(1);
}
out_col = (cell_max_width + rdd_char_num * 2 + 1) * table_col + 1;
if(out_col > out_max_col){
puts("ERROR: out_col > out_max_col"); return(1);
}
/* table_hori_line を作成 */
{ //一時変数隠蔽用ブロック
int hori_line_crr;
int temp;
int cell_width;
table_hori_line[0] = '+';
hori_line_crr = 1;
for(i = 0; i < table_col; i++){
temp = 0;
cell_width = col_cell_width[i] + rdd_char_num * 2;
while(temp < cell_width){
table_hori_line[hori_line_crr] = '-';
hori_line_crr++;
temp++;
}
table_hori_line[hori_line_crr] = '+';
hori_line_crr++;
}
}
/* output にtableを書き出し */
{ //一時変数隠蔽用ブロック
int out_crr_col;
int out_crr_row;
char *crr_cell_str_ptr;
int crr_cell_str_size;
int first_space_size;
int last_space_size;
int temp;
out_crr_col = 0;
out_crr_row = 0;
for(i = 0; i < table_row; i++){
if(i == 0){
for(out_crr_col = 0; out_crr_col < out_col; out_crr_col++){
output[out_crr_row][out_crr_col] = table_hori_line[out_crr_col];
}
out_crr_row++;
}
out_crr_col = 0;
output[out_crr_row][out_crr_col] = '|';
out_crr_col++;
for(j = 0; j < table_col; j++){
crr_cell_str_ptr = table[i][j].ptr;
crr_cell_str_size = table[i][j].size;
switch(mode_str_pos){
case MEDIUM:
//中央配置
if( (col_cell_width[j] + crr_cell_str_size) % 2 == 0){
first_space_size = (col_cell_width[j] - crr_cell_str_size) / 2;
last_space_size = (col_cell_width[j] - crr_cell_str_size) / 2;
}
else{
first_space_size = (col_cell_width[j] - crr_cell_str_size) / 2;
last_space_size = (col_cell_width[j] - crr_cell_str_size) / 2 + 1;
}
break;
case LEFT:
//左詰め
first_space_size = 0;
last_space_size = col_cell_width[j] - crr_cell_str_size;
break;
case RIGHT:
//右詰め
first_space_size = col_cell_width[j] - crr_cell_str_size;
last_space_size = 0;
break;
default:
puts("'mode_str_pos' has invalid value"); return(1);
break;
}
//冗長文字の書き込み
for(temp = 0; temp < rdd_char_num; temp++){
output[out_crr_row][out_crr_col] = rdd_char;
out_crr_col++;
}
//文字列の前の空白文字を書き込む
for(temp = 0; temp < first_space_size; temp++){
output[out_crr_row][out_crr_col] = space_char;
out_crr_col++;
}
//セルの文字列の書き込み
for(temp = 0; temp < crr_cell_str_size; temp++){
output[out_crr_row][out_crr_col] = crr_cell_str_ptr[temp];
out_crr_col++;
}
//文字列の後の空白文字を書き込む
for(temp = 0; temp < last_space_size; temp++){
output[out_crr_row][out_crr_col] = space_char;
out_crr_col++;
}
//冗長文字の書き込み
for(temp = 0; temp < rdd_char_num; temp++){
output[out_crr_row][out_crr_col] = rdd_char;
out_crr_col++;
}
//壁 '|'を書き込む
output[out_crr_row][out_crr_col] = '|';
out_crr_col++;
}
out_crr_row++;
for(out_crr_col = 0; out_crr_col < out_col; out_crr_col++){
output[out_crr_row][out_crr_col] = table_hori_line[out_crr_col];
}
out_crr_row++;
}
}
return(0);
}
void show_input(char input[][in_max_col]){
int i = 0;
while(i < in_max_row && input[i][0] != '\0'){
i++;
}
}
void show_output(char output[][out_max_col]){
int i = 0;
while(i < out_max_row && output[i][0] != '\0'){
i++;
}
}
int main(void){
char input[in_max_row][in_max_col] = { "a|eeeee||123456789|abcdefg|qwertyuiop|asdxfghjkl",
"bb|ffffff",
"ccc|ggggggg||0|1|2|3",
"dddd|hhhhhhhh||4|5|6|7|" };
char output[out_max_row][out_max_col];
show_input(input);
if(tbl(output, input, MEDIUM, MAX_IN_EACH_COL) != 0){
}
show_output(output);
if(tbl(output, input, LEFT, MAX_IN_EACH_COL) != 0){
}
show_output(output);
if(tbl(output, input, RIGHT, MAX_IN_EACH_COL) != 0){
}
show_output(output);
if(tbl(output, input, MEDIUM, MAX_IN_TABLE) != 0){
}
show_output(output);
if(tbl(output, input, LEFT, MAX_IN_TABLE) != 0){
}
show_output(output);
if(tbl(output, input, RIGHT, MAX_IN_TABLE) != 0){
}
show_output(output);
return 0;
}