fork download
/*
プログラミングのお題スレ 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'){
    printf("%s\n", input[i]);
    i++;
  }
  puts("");
}

void show_output(char output[][out_max_col]){
  int i = 0;
  while(i < out_max_row && output[i][0] != '\0'){
    printf("%s\n", output[i]);
    i++;
  }
  puts("");
}

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];

  puts("入力: ");
  show_input(input);
  
  puts("各列ごとに幅変更、中間配置");
  if(tbl(output, input, MEDIUM, MAX_IN_EACH_COL) != 0){
    exit(1);
  }
  show_output(output);

  puts("各列ごとに幅変更、左詰め");
  if(tbl(output, input, LEFT, MAX_IN_EACH_COL) != 0){
    exit(1);
  }
  show_output(output);

  puts("各列ごとに幅変更、右詰め");
  if(tbl(output, input, RIGHT, MAX_IN_EACH_COL) != 0){
    exit(1);
  }
  show_output(output);

  puts("全セル等幅、中間配置");
  if(tbl(output, input, MEDIUM, MAX_IN_TABLE) != 0){
    exit(1);
  }
  show_output(output);
  
  puts("全セル等幅、左詰め");
  if(tbl(output, input, LEFT, MAX_IN_TABLE) != 0){
    exit(1);
  }
  show_output(output);

  puts("全セル等幅、右詰め");
  if(tbl(output, input, RIGHT, MAX_IN_TABLE) != 0){
    exit(1);
  }
  show_output(output);
  
  return 0;
}
Success #stdin #stdout 0s 9432KB
stdin
Standard input is empty
stdout
入力: 
a|eeeee||123456789|abcdefg|qwertyuiop|asdxfghjkl
bb|ffffff
ccc|ggggggg||0|1|2|3
dddd|hhhhhhhh||4|5|6|7|

各列ごとに幅変更、中間配置
+------+----------+--+-----------+---------+------------+------------+
| *a** | *eeeee** |  | 123456789 | abcdefg | qwertyuiop | asdxfghjkl |
+------+----------+--+-----------+---------+------------+------------+
| *bb* | *ffffff* |  | ********* | ******* | ********** | ********** |
+------+----------+--+-----------+---------+------------+------------+
| ccc* | ggggggg* |  | ****0**** | ***1*** | ****2***** | ****3***** |
+------+----------+--+-----------+---------+------------+------------+
| dddd | hhhhhhhh |  | ****4**** | ***5*** | ****6***** | ****7***** |
+------+----------+--+-----------+---------+------------+------------+

各列ごとに幅変更、左詰め
+------+----------+--+-----------+---------+------------+------------+
| a*** | eeeee*** |  | 123456789 | abcdefg | qwertyuiop | asdxfghjkl |
+------+----------+--+-----------+---------+------------+------------+
| bb** | ffffff** |  | ********* | ******* | ********** | ********** |
+------+----------+--+-----------+---------+------------+------------+
| ccc* | ggggggg* |  | 0******** | 1****** | 2********* | 3********* |
+------+----------+--+-----------+---------+------------+------------+
| dddd | hhhhhhhh |  | 4******** | 5****** | 6********* | 7********* |
+------+----------+--+-----------+---------+------------+------------+

各列ごとに幅変更、右詰め
+------+----------+--+-----------+---------+------------+------------+
| ***a | ***eeeee |  | 123456789 | abcdefg | qwertyuiop | asdxfghjkl |
+------+----------+--+-----------+---------+------------+------------+
| **bb | **ffffff |  | ********* | ******* | ********** | ********** |
+------+----------+--+-----------+---------+------------+------------+
| *ccc | *ggggggg |  | ********0 | ******1 | *********2 | *********3 |
+------+----------+--+-----------+---------+------------+------------+
| dddd | hhhhhhhh |  | ********4 | ******5 | *********6 | *********7 |
+------+----------+--+-----------+---------+------------+------------+

全セル等幅、中間配置
+------------+------------+------------+------------+------------+------------+------------+
| ****a***** | **eeeee*** | ********** | 123456789* | *abcdefg** | qwertyuiop | asdxfghjkl |
+------------+------------+------------+------------+------------+------------+------------+
| ****bb**** | **ffffff** | ********** | ********** | ********** | ********** | ********** |
+------------+------------+------------+------------+------------+------------+------------+
| ***ccc**** | *ggggggg** | ********** | ****0***** | ****1***** | ****2***** | ****3***** |
+------------+------------+------------+------------+------------+------------+------------+
| ***dddd*** | *hhhhhhhh* | ********** | ****4***** | ****5***** | ****6***** | ****7***** |
+------------+------------+------------+------------+------------+------------+------------+

全セル等幅、左詰め
+------------+------------+------------+------------+------------+------------+------------+
| a********* | eeeee***** | ********** | 123456789* | abcdefg*** | qwertyuiop | asdxfghjkl |
+------------+------------+------------+------------+------------+------------+------------+
| bb******** | ffffff**** | ********** | ********** | ********** | ********** | ********** |
+------------+------------+------------+------------+------------+------------+------------+
| ccc******* | ggggggg*** | ********** | 0********* | 1********* | 2********* | 3********* |
+------------+------------+------------+------------+------------+------------+------------+
| dddd****** | hhhhhhhh** | ********** | 4********* | 5********* | 6********* | 7********* |
+------------+------------+------------+------------+------------+------------+------------+

全セル等幅、右詰め
+------------+------------+------------+------------+------------+------------+------------+
| *********a | *****eeeee | ********** | *123456789 | ***abcdefg | qwertyuiop | asdxfghjkl |
+------------+------------+------------+------------+------------+------------+------------+
| ********bb | ****ffffff | ********** | ********** | ********** | ********** | ********** |
+------------+------------+------------+------------+------------+------------+------------+
| *******ccc | ***ggggggg | ********** | *********0 | *********1 | *********2 | *********3 |
+------------+------------+------------+------------+------------+------------+------------+
| ******dddd | **hhhhhhhh | ********** | *********4 | *********5 | *********6 | *********7 |
+------------+------------+------------+------------+------------+------------+------------+