C#とClosedXmlで、結合されたエクセルのセルを判定してみた

どもです。
今回は、C#/ClosedXmlを用いて、エクセルファイルの結合されたセルの判定をしてみた内容について書きます。

1.開発環境

まず、今回のエントリの開発環境です。

開発環境
CPU i7-8700 CPU 3.20GHz
メモリ 16.0GB
OS Windows10 Pro
Version 2004
ビルド 19041.867
IDE VisualStudioCommunity 2019
Version 16.8.6
開発言語 C#
フレームワーク .NET Framework 4.7
ClosedXml 0.95.4

2.背景(簡単に)

以前のエントリで、エクセルに記入した関数定義からスタブを生成するツールについて書きました。
そのツールでは、関数の名前や変数の定義の範囲を、文字列検索を行って取得していました。
この方法では修正・変更が大変です。
そこで、より良い方法、実装がないか調査・検討を行ってみました。

3.ClosedXmlでのセルの結合の判定

3.1.結合されているか否かの判定

ClosedXmlでセルが結合されているか否かを判定する際には、「isMerged」メソッドを使用します。
具体的なコードは、以下になります。

workSheet.Cell(rowIndex, colIndex).IsMerged();

具体例として、以下のシートを読み込んでみます。

読み込みと結果の表示を行うコードは、以下になります。

string inputFilePath = @".\CellMergeSample.xlsx";
using (var excelStream = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
	string sampleSheetName = "CellMergeSample";
	var workBook = new XLWorkbook(excelStream, XLEventTracking.Disabled);
	var workSheet = workBook.Worksheet(sampleSheetName);

	//結合されている/されていないを、セル単位で判定。
	for (int rowIndex = 1; rowIndex < 10; rowIndex++)
	{
		if (workSheet.Cell(rowIndex, 2).IsMerged())
		{
			Console.WriteLine($"{workSheet.Cell(rowIndex, 2).Address} : 結合されています。");
		}
		else
		{
			Console.WriteLine($"{workSheet.Cell(rowIndex, 2).Address} : 結合されていません。");
		}
	}
}

で、実行結果は下図です。

この結果から確認できるとおり、セルが結合されている/されていないの判定ができています。
しかしながら、「VerticalMerge1」と「VerticalMerge2」の区別、境目を判定ができていません。

3.2.セルの結合範囲の判定

そこで次に、結合されたセルの範囲を確認する方法について調べてみました。

3.2.1.結合範囲の取得

結合範囲は、「MergedRange()」によりIXLRangeオブジェクトで取得できます。

3.2.2.結合範囲の開始と終了位置

結合範囲の開始位置と終了位置は、IXLRangeオブジェクトの「FirstRow()」メソッドと「LastRow()」メソッドで取得ができます。
この2つのメソッドは、「IXLRangeRow」オブジェクトを返します。
そのため具体的な行番号は、「RowNumber()」メソッドで取得できます。

3.3.セルの結合範囲を取得する実装

前章の内容を適用した結合範囲を判定、結合された範囲を取得する処理を、以下のように実装してみました。

//結合された範囲の取得
for (int rowIndex = 1; rowIndex < 16; rowIndex++)
{
	if (workSheet.Cell(rowIndex, 2).IsMerged())
	{
		var cell = workSheet.Cell(rowIndex, 2);
		Console.WriteLine($"RowCount = {cell.MergedRange().FirstRow().RowNumber()}");
		Console.WriteLine($"RowCount = {rowIndex}, FirstRow = {cell.MergedRange().FirstRow().RowNumber()}, LastRow = {cell.MergedRange().LastRow().RowNumber()}");
	}
}

この処理を、「2.1.」で示したコードの下に追加して実行した結果が、下図になります。

図を見て分かるように行番号が2~5の範囲、最初に示した図での「VerticalMerge1」に対応するセルについては、開始行と終了行がそれぞれ2と5が取得できています。
また「VerticalMerge2」に対応するセルについては、開始行と終了行がそれぞれ6と9が取得できています。
このことから、結合された範囲の開始行と終了行が取得できていることが分かります。

3.4.列は…?

行が取得できることは分かりましたが、列はどうでしょう?
これは簡単です。
IXLRangeオブジェクトは、行の判定の際に使用した関数の「Row」を「Column」に変更したメソッドを提供しています。
これらのメソッドを使用すれば、列に関しても結合範囲が取得できます。

4.まとめ

今回は、C#/ClosedXmlを用いて、エクセルファイルの結合されたセルの判定をしてみました。
IsMerged()メソッドを用いれば、セルが結合されているか否かは簡単に判断できました。
結合された範囲(開始行(列)/終了行(列))については、IXLRangeオブジェクトのメソッド、FirstRow()またはFirstColumn()メソッドを使用することで、結合された行と列の開始位置を取得できます。
また、LastRow()またはLastColumn()メソッドを使用することで、結合された行と列の終了位置を取得できます。

今後ClosedXmlを用いてエクセルの内容を取得する際には、これらの方法を使用して結合の判定と結合された範囲の取得を行っていこうと思います。

ではっ!