LoginSignup
6
4

More than 5 years have passed since last update.

Excel主義者はきれいな表が好き(見かけだけ)

Last updated at Posted at 2017-10-18

Excel主義者はきれいな表が好き(単に見かけだけ)

Excel主義者はともかくきれいな表が好き。きれいというのは、単に見かけだけで、セル結合したり、罫線で囲った表は、再利用がほとんど不可能だ。

この1カ月、ともかくExcelの表に苦しんだ。

そもそも罫線なのか図形なのか不明。
罫線で囲んだ文字を移動しようとすると、罫線がついてこない。
罫線で囲んだ文字がフォントを変更すると一部見えなくなるが、罫線を拡大できない。
罫線のある表を拡大縮小できない。
罫線のある表を無理に拡大縮小すると、枠の罫線がでこでこになる。
30ピクセルのExcel方眼紙を突如20ピクセルに変更することになり、図が全部縦長に。シネスコの映画をスタンダードにしたみたい。
結合してあるので、一部だけを移動できない。謎のメッセージ。
結合してある表を選択してコピーしてもコピーできない…。コピーできないっていったいどういうことだ!

もうへとへとです。

そこにとなりからExcel主義者の軽快なキーボード操作(単調なコピーペーストと移動)の繰り返しがリズミカルに響いてくる。
この単調なリズムは、究極の手作業をしている感じ。

さて、そう歎いていてもしかたない。プログラムでなんとかできることはしようということで、やってみた。

まずテキストは、こんな感じ。

見出し   1.画面コントロール

ID/2    名称/9    コントロール名/6 I・O/2 必須/2    説明/20   取得DB名/5   取得カラム名/5
1   タイトル    ラベル   O   -   タイトルを示すラベル。   -   -
2   ユーザID ラベル   O   -   IDの入力位置を示すラベル。  -   -
3   ユーザID テキストボックス    O   -   登録用のユーザIDを表示するテキストボックス。変更不可。    LoginDB ID
4   ユーザ名    ラベル   O   -   ユーザ名の入力位置を示すラベル。    -   -
5   ユーザ名    テキストボックス    I   ○ 登録用のユーザ名を入力するテキストボックス。  LoginDB UserName
6   パスワード ラベル   O   -   PWの入力位置を示すラベル。  -   -
7   パスワード Hiddenテキストボックス  I   -   PWを入力するテキストボックス。    -   -
8   パスワード(確認) ラベル   O   -   PWの入力位置を示すラベル。  -   -
9   パスワード(確認) Hiddenテキストボックス  I   -   確認用PWを入力するテキストボックス。入力文字は分からないように表示する。 -   -
10  キャンセル ボタン   I   -   処理を中止するボタン。一覧に戻る。 -   -
11  変更  ボタン   I   -   入力内容をチェックして変更するボタン。一覧に戻る。 -   -

見出し   2.イベント処理

No./2   種類/10   説明/39
1   変更ボタン押下時    1.入力チェック(3.2チェック参照)☆ OKの場合2へ。☆ NGの場合エラーメッセージを表示。☆2.ユーザ名チェック(3.2チェック参照)☆ NGの場合エラーメッセージを表示。☆3.画面遷移。☆・3.1 ユーザ変更OKの場合管理者:ユーザ管理(一覧)画面に遷移。☆ NGの場合エラーメッセージを表示。☆・3.2 ユーザ変更OKの場合ユーザ:画面に遷移。☆ NGの場合エラーメッセージを表示。
2   キャンセルボタン押下時   2.画面遷移。☆・2.1 管理者:ユーザ管理(一覧)画面に遷移。☆・2.2 ユーザ:ログイン画面に遷移。
3   パスワード(確認)ロストフォーカス時  1.入力チェック(3.2チェック参照)☆ OKの場合なにもしない。☆ NGの場合エラーメッセージを表示。

見出し   3.チェック

No./2   種類/14   説明/23   表示エラーメッセージ/16
1   PW文字チェック    入力したPWを相互にチェック。   PWが異なります。
2   必須チェック  入力項目の必須文字の入力を促す。    ユーザ名が空です。

見出し   4.特記事項

Markup

ユーザー管理(変更画面)の仕様書と思ってほしい。
ほとんどは平文だが、ごく少量マークアップの文字を使っている。

そもそも「見出し」とテーブルがあり、それぞれは改行ふたつで区切る。
見出しは「見出し」タブと書く。

テーブルは、1行目がヘッダ行となる。
ヘッダ行は、/2で結合するセルの数を示す。/2ならふたつのセルを結合するという意味。
この結合数をマーキングするために、「/」を使っているので、本文では/を使用できない。このあたりはすこし検討の余地がある。
セル内改行(\n)に☆を使っている。

たとえば見出しを####にすれば、Markdownにそっくりになる。
とはいえ、このテキスト、ほとんどテキストといっていいと思う。タブ区切りで素性もいいと思う。
これを下記のコードを通すと、じゃーん! Excelの表のできあがりである。できた表はぜひご自分で確かめられたい。

これを拡張すれば、txt2xlsxとなるなと思っている。

code

string excelfilepath= "";
using (var book = new XLWorkbook(excelfilepath))
{
var sheet = book.Worksheet(sheetname);
string path = @"text.txt";
var lastusedlinenumber = sheet.LastRowUsed().RangeAddress.LastAddress.RowNumber;
Cell cell = new Cell("C", lastusedlinenumber+2);
string[] tables =File.ReadAllText(path, Encoding.UTF8).Split(new string[] { "\r\n\r\n" }, StringSplitOptions.None);
foreach(var table in tables)
{
    List<int> cellwidths = new List<int>();
    if (string.IsNullOrEmpty(table.Trim())) continue;
    if (table.Contains("見出し"))
    {
        int targetline = cell.LineNumber + 2;
        string[] cells = table.TrimEnd().Split(new string[] { "\r\n", "\r", "\n", "\t" }, StringSplitOptions.None);
        string startcell = "B";
        ExcelOperation.SetCellValue(sheet, startcell + targetline, cells[1]);
        sheet.Range(startcell + targetline + ":" + startcell + targetline).Style.Font.FontSize = 11;
        cell.LineNumber = cell.LineNumber + 4;
    }
    else
    {
        string[] lines = table.TrimEnd().Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
        foreach (var line in lines.Select((Value, Index) => new { Value, Index }))
        {
            if (line.Value.Contains("/"))
                cellwidths.Clear();
            int targetline = cell.LineNumber + line.Index;
            string[] cells = line.Value.TrimEnd().Split(new string[] { "\t" }, StringSplitOptions.None);
            string endcell = cell.HeadCell;
            foreach (var c in cells.Select((Value, Index) => new { Value, Index }))
            {
                string[] cellvalues = c.Value.Split(new string[] { "/" }, StringSplitOptions.None);
                //結合セル
                int cellwidth = 4;
                if (1 < cellvalues.Length) cellwidth = int.Parse(cellvalues[1]);
                if (c.Value.Contains("/")) cellwidths.Add(cellwidth);
                else if (c.Index < cells.Length) cellwidth = cellwidths[c.Index];

                string startcell = endcell;
                endcell = cell.ToAlphabet(cell.ToInt(startcell) + cellwidth - 1);
                ExcelOperation.SetCellValue(sheet, startcell + targetline, cellvalues[0].Replace("☆", "\n").Replace("I・O", "I/O"));
                sheet.Range(startcell + targetline + ":" + endcell + targetline).Merge().Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
                sheet.Range(startcell + targetline + ":" + endcell + targetline).Style.Alignment.WrapText = true;
                sheet.Range(startcell + targetline + ":" + startcell + targetline).Style.Font.FontSize = 9;

                //見出し行
                if (line.Index == 0 || line.Value.Contains("/"))
                {
                    sheet.Range(startcell + targetline + ":" + endcell + targetline).Style.Fill.BackgroundColor = XLColor.LightGray;
                    sheet.Range(startcell + targetline + ":" + endcell + targetline).Style.Font.Bold = true;
                    sheet.Range(startcell + targetline + ":" + endcell + targetline).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
                }

                endcell = cell.ToAlphabet(cell.ToInt(startcell) + cellwidth);
            }
        }
        cell.LineNumber = cell.LineNumber + lines.Length + 3;
    }
}

book.SaveAs(savename);

注記

使用には、ClosedXMLが必要。
別途。Cellクラスというクラスを作っている。セル文字と行を管理しているだけなので、なくても動く。

やっているのは、テキストを行のかたまり=tableにわけ、見出しとテーブルとで処理をわけている。テーブルは、1行目をヘッダ行として特別扱いし、結合するセルの個数をもって、テーブルぜんたいに適応している。

テキストをレイアウトしたあとに、セルを結合し、周囲に罫線を引いている。
という感じ。

これで業務でじっさいに表を作って、かなり省力化できた。ともかく表を作り直すのが楽。検索もできるし、置換もしやすい。
いや作ってよかった。
感覚的にはTeXみたいな感じ。

ToDo

今後の、ほぼやらないけど課題と感じていることを、いちおう書き出しておこう。

見出しを####に対応して、Markdown的に拡張することを検討。
コードを整理。リファクタリング。
「/」を区切り文字に使うのをやめる。
セルのheightに対応する。
結合セル数を自動指定。これができれば/2のような指定も不要。
セルによってセンタリングと左寄せを使い分け。

仕様書は書き終わったので目的は達成しているので、よほど気が向いて時間があって、ほかにすることがなければ。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4