S-JIS[2014-05-03/2020-09-12] 変更履歴

Apache POI Cell

POI3.10以降でExcelファイルのセルを操作する方法について。


概要

Excelのセルは、POIではCellクラスで扱う。

Cellからセルの値を取得できるが、保持している値の型(数値か文字列か等)に応じて値の取得メソッドが異なる。

また、結合セルの場合も値の取得方法が異なる。


セルの取得

ワークシートを表すSheetオブジェクトからgetRow()でロー(行)を取得し、そこからgetCell()でセルを取得する。getRow()やgetCell()の引数は0オリジンである。
データの無い行やセルではnullが返ってくるので、nullチェックは必須。

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
		Sheet sheet = ;
		Cell cell = getCell(sheet, 0, 0);
	public static Cell getCell(Sheet sheet, int rowIndex, int columnIndex) {
		Row row = sheet.getRow(rowIndex);
		if (row != null) {
			Cell cell = row.getCell(columnIndex);
			return cell;
		}
		return null;
	}

A1形式でインデックスを取得する方法


セルに値をセットする目的でCellを取得したい場合は、CellUtilを使うと便利。[2014-10-05]

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellUtil;
		Row row = CellUtil.getRow(rowIndex, sheet);
		Cell cell = CellUtil.getCell(row, columnIndex);
		cell.setCellValue("zzz");

CellUtilのgetRow()やgetCell()では、存在しない行・セルの場合はインスタンスを作って返してくれる。


セルの存在する範囲の取得

ワークシート内でデータのあるセルの範囲(最小・最大位置(インデックス))を取得することが出来る。

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
	public static void limit(Sheet sheet) {
		System.out.println(sheet.getFirstRowNum());
		System.out.println(sheet.getLastRowNum());

		Row row = sheet.getRow(sheet.getFirstRowNum());
		System.out.println(row.getFirstCellNum());
		System.out.println(row.getLastCellNum());
	}

セルの値の取得

セルから値を取得するには、まずセルの型(cellType)を取得し、それに応じて取得メソッドを呼び出す。

import org.apache.poi.ss.usermodel.Cell;
	// セルの値をStringとして取得する例
	public static String getStringValue(Cell cell) {
		if (cell == null) {
			return null;
		}
		switch (cell.getCellType()) {
		case Cell.CELL_TYPE_STRING:
			return cell.getStringCellValue();
		case Cell.CELL_TYPE_NUMERIC:
			return Double.toString(cell.getNumericCellValue());
		case Cell.CELL_TYPE_BOOLEAN:
			return Boolean.toString(cell.getBooleanCellValue());
		case Cell.CELL_TYPE_FORMULA:
			// return cell.getCellFormula();
			return getStringFormulaValue(cell);
		case Cell.CELL_TYPE_BLANK:
			return getStringRangeValue(cell);
		default:
			System.out.println(cell.getCellType());
			return null;
		}
	}

cellTypeがCELL_TYPE_FORMULAの場合はセルの内容が計算式(数式)なので、その計算を行う必要がある。
(getCellFormula()は数式自体を取得する)

CELL_TYPE_BLANKの場合は、結合されたセルである可能性がある。
結合セルの情報は別の場所で保持されているので、そちらを参照する必要がある。


セルの数式の計算

cellTypeがCELL_TYPE_FORMULAの場合はセルの内容が計算式(数式)であり、その計算を実行して値を取得することが出来る。

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Workbook;
	// セルの数式を計算し、Stringとして取得する例
	public static String getStringFormulaValue(Cell cell) {
		assert cell.getCellType() == Cell.CELL_TYPE_FORMULA;

		Workbook book = cell.getSheet().getWorkbook();
		CreationHelper helper = book.getCreationHelper();
		FormulaEvaluator evaluator = helper.createFormulaEvaluator();
		CellValue value = evaluator.evaluate(cell);
		switch (value.getCellType()) {
		case Cell.CELL_TYPE_STRING:
			return value.getStringValue();
		case Cell.CELL_TYPE_NUMERIC:
			return Double.toString(value.getNumberValue());
		case Cell.CELL_TYPE_BOOLEAN:
			return Boolean.toString(value.getBooleanValue());
		default:
			System.out.println(value.getCellType());
			return null;
		}
	}

参考: しんさんのPOIでセルの値をとるのは大変 数式編

キャッシュされている計算結果の取得
計算式(数式)の解析・変更


セルの数式のキャッシュされた値の取得

cellTypeがCELL_TYPE_FORMULAの場合、セルに保存されている計算結果を取得できる。[2017-01-28]

キャッシュされている値の型(数値か文字列か等)はgetCachedFormulaResultTypeメソッドで取得できる。
後は、それに応じたgetCellValueメソッドを呼び出す(数式以外の値の取得方法と全く同じ)。

	// セルにキャッシュされている値をStringとして取得する例
	public static String getStringCachedFormulaValue(Cell cell) {
		assert cell.getCellType() == Cell.CELL_TYPE_FORMULA;

		switch (cell.getCachedFormulaResultType()) {
		case Cell.CELL_TYPE_STRING:
			return cell.getStringCellValue();
		case Cell.CELL_TYPE_NUMERIC:
			return Double.toString(cell.getNumericCellValue());
		case Cell.CELL_TYPE_BOOLEAN:
			return Boolean.toString(cell.getBooleanCellValue());
		default:
			System.out.println(cell.getCachedFormulaResultType());
			return null;
		}
	}

なお、計算結果がキャッシュされていない場合は数値扱い(CELL_TYPE_NUMERIC)で、getNumericCellValueは0が返るようだ。
(キャッシュされているかどうかを判定する方法は不明)

数式を計算する方法


結合セルの取得

結合セルの場合、値が入っているのは一番左上のセルになる。
結合セルで左上以外のセルの場合はcellTypeがCELL_TYPE_BLANKになってるっぽいので、その場合は左上のセルを取得してくればよい。
(変な作り方をしたExcelの場合は、左上以外でも値が入っていることがあるっぽい。つまり左上以外が常にCELL_TYPE_BLANKになっているとは限らない。[2014-10-05]

結合セルの情報は(Sheet#getRow()等では取得できず、)Sheetの別の場所に保存されている。

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
	// 結合セルの値をStringとして取得する例
	public static String getStringRangeValue(Cell cell) {
		int rowIndex = cell.getRowIndex();
		int columnIndex = cell.getColumnIndex();

		Sheet sheet = cell.getSheet();
		int size = sheet.getNumMergedRegions();
		for (int i = 0; i < size; i++) {
			CellRangeAddress range = sheet.getMergedRegion(i);
			if (range.isInRange(rowIndex, columnIndex)) {
				Cell firstCell = getCell(sheet, range.getFirstRow(), range.getFirstColumn()); // 左上のセルを取得
				return getStringValue(firstCell);
			}
		}
		return null;
	}

参考: OKWaveのJakarta POI のHSSFで結合セル情報の取得

セルを結合する方法


SheetクラスにはMergedResionのリストを返すgetMergedRegionsメソッドがあるが、内部でArrayListを作って返すので、メモリー使用効率的にはgetMergedRegionを使う方が良さげ。(インデックスアクセスは野暮ったいけど…)[2020-09-12]

いずれにしても、特にxlsxファイルではgetMergedRegionメソッドによる値の取得が若干遅いようで、結合セルが大量にあると検索に時間がかかる。
検索を頻繁に行うようなら、Mapに変換して探索する等の工夫が必要。

例:MergedRegionMap.java


セルのエラー値の取得

cellTypeがCELL_TYPE_ERRORの場合はセルの内容はエラーとなっている。[2015-10-04]

セルがエラーになっている場合、Cell#getErrorCellValue()でエラーコードを取得できる。
このエラーコードに対応している列挙型がFormulaError。

import org.apache.poi.ss.usermodel.FormulaError;

FormulaErrorからエラー文字列(「#VALUE!」とか)を取得することが出来る。

		if (cell.getCellType() == Cell.CELL_TYPE_ERROR) {
			byte errorCode = cell.getErrorCellValue();
			FormulaError error = FormulaError.forInt(errorCode);
			String errorText = error.getString();
			〜
		}

日付の取得

Excelのセルに日付が入っている場合、データの実体としては数値であり、書式で日付として表示しているだけである。
したがって、POIで日付を扱う際も値を数値(CELL_TYPE_NUMERIC)として取得し、日付に変換してやる。

import java.util.Date;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
	public static Date getDateValue(Cell cell) {
//		if (DateUtil.isCellDateFormatted(cell)) {
			double value = cell.getNumericCellValue();
			return DateUtil.getJavaDate(value);
//		}
//		return null;
	}

Cell自身にもgetDateCellValue()メソッドがあり、内部では似たような事をしている。[2014-10-22]

	public static Date getDateValue(Cell cell) {
		return cell.getDateCellValue();
	}

コメントの取得

セルに設定されたコメントを取得するには、Cell#getCellComment()を使うか、Sheet#getCellComment(row, column)を使う。[2014-10-22]
(→コメントの設定

import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.RichTextString;
//		Comment comment = sheet.getCellComment(1, 1);
		Comment comment = cell.getCellComment();

		String author = comment.getAuthor();
		System.out.printf("author=%s\n", author);

		RichTextString richString = comment.getString();
		System.out.println(richString.getString());

コメントを設定する際にはコメント領域の位置・大きさを示すAnchorオブジェクトを指定するのだが、3.10-FINALではAnchorを取得する方法は提供されていない。

HSSFの場合はHSSFCommentから取得できる。

import org.apache.poi.hssf.usermodel.HSSFComment;
import org.apache.poi.ss.usermodel.ClientAnchor;
		ClientAnchor anchor = (ClientAnchor) ((HSSFComment) comment).getAnchor();

POI 3.11以降は以下の方法で取得できる。(プルリクエストしたらマージされた)[2017-02-18]

		ClientAnchor anchor = comment.getClientAnchor();

セルの値設定

セルに値を設定するにはsetCellValue()を使う。[2014-10-06]
値を取得するときはセルの型(cellType)を取得してそれに応じた取得メソッドを使う必要があったが、値をセットするメソッドはオーバーロードされているので、メソッド名としては一種類。

		cell.setCellValue("abc"); // String
		cell.setCellValue(123);   // double
		cell.setCellValue(true);  // boolean
		cell.setCellValue(date);  // java.util.Date

ただ、さすがに計算式(CELL_TYPE_FORMULA)をセットするには別のメソッドを使う必要がある。

		cell.setCellFormula("A1");

コメントの設定

セルにコメントを設定するにはsetCellComment()を使う。[2014-10-22]
(→コメントの取得

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.RichTextString;
	private static void setCellComment(Cell cell, String author, String text) {
		Sheet sheet = cell.getSheet();
		Workbook workbook = sheet.getWorkbook();
		CreationHelper helper = workbook.getCreationHelper();

		int dx1 = 200, dy1 = 100, dx2 = 200, dy2 = 100;
		int col1 = cell.getColumnIndex() + 1, row1 = cell.getRowIndex();
		int col2 = col1 + 1, row2 = row1 + 2;
		Drawing drawing = sheet.createDrawingPatriarch();
		ClientAnchor anchor = drawing.createAnchor(dx1, dy1, dx2, dy2, col1, row1, col2, row2);
		Comment comment = drawing.createCellComment(anchor);
		comment.setAuthor(author);
		comment.setString(helper.createRichTextString(text));
		cell.setCellComment(comment);
	}

Commentオブジェクトには、コメントを書いた人(author)とコメント文字列(RichTextString)をセットする。

その他に、コメント領域の大きさおよびコメント編集時の座標をAnchorで指定する。
col1,row1がコメント編集時のコメント領域の左上の位置を示す。
col2,row2でコメント編集時のコメント領域の右下の位置を示す。
これらはセルの行インデックス・列インデックスで指定する。
コメントの表示および編集時のコメント領域の大きさは、col2-col1,row2-row1で決まる。
dx1,dy1およびdx2,dy2は、col1,row1およびcol2,row2の位置の微調整を行う。dx1,dy1,dx2,dy2の分だけコメント編集時のコメント領域の位置がずれる。
もしdx1,dy1,dx2,dy2が全て0ならば、コメント領域の大きさはセルの大きさと全く同じになり、コメント編集時のコメント領域の位置もセルとぴったり重なる。

Commentオブジェクトは設置されているセルの座標を保持しているので、同一オブジェクトを使い回す(別のセルに設定する)ことは出来ない。

セルに設定されているコメントを削除するには、Cell#setCellComment()にnullを渡すか、Cell#removeCellComment()を呼び出す。


ハイパーリンクの設定

セルにハイパーリンクを設定すると、そのセルをクリックしたときにハイパーリンク先にジャンプすることが出来る。[2014-10-06]

import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Hyperlink;
		CreationHelper helper = workbook.getCreationHelper();
		Hyperlink link = helper.createHyperlink(Hyperlink.LINK_DOCUMENT); //Excelシートへのジャンプ
		link.setAddress("sheet2!B2"); //ジャンプ先はsheet2のB2セル
		cell.setHyperlink(link);
		cell.setCellValue("ハイパーリンクによるジャンプ");

		// フォントの設定
		Font font = workbook.createFont();
		font.setColor(IndexedColors.BLUE.getIndex());
		font.setUnderline(Font.U_SINGLE);
		CellStyle style = workbook.createCellStyle();
		style.setFont(font);
		cell.setCellStyle(style);

普通にExcel上でハイパーリンクを作ると字が青くなって下線が引かれるが、これはセルのスタイル(フォント)を別途定義する必要がある。

参考: JavaDriveのハイパーリンクの設定


POI 3.11以降はセルからハイパーリンクを削除することが出来る。(プルリクエストしたらマージされた)[2017-02-18]

		cell.setHyperlink(null);

あるいは

		cell.removeHyperlink();

セルの結合

セルを結合するには、Sheetに対して結合情報を追加する。[2014-10-11]
(→結合セルの取得

Cellそのものは、そのセル自身が結合されているのかどうかの情報を持っていない。
Sheetに結合情報(結合された範囲の一覧)が保持されている。

import org.apache.poi.ss.util.CellRangeAddress;
		int firstRow = 0;
		int lastRow = 1;
		int firstColumn = 0;
		int lastColumn = 1;
		CellRangeAddress region = new CellRangeAddress(firstRow, lastRow, firstColumn, lastColumn);
		sheet.addMergedRegion(region);
		CellRangeAddress region = CellRangeAddress.valueOf("A1:B2");
		sheet.addMergedRegion(region);

なお、セルのスタイルに関しては、背景色は左上のセルの設定が使われ、枠線に関してはそれぞれのセルの設定が生きるようだ。


プルダウンの設定

セルにプルダウンを設定して、入力できる値を制限することが出来る。[2014-10-11]
これは、入力規則の設定となる。

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddressList;
		Cell cell = 〜; // プルダウンを設定したい対象のセル

		Sheet sheet = cell.getSheet();
		DataValidationHelper helper = sheet.getDataValidationHelper();

		// プルダウンに表示する値一覧
		DataValidationConstraint constraint = helper.createFormulaListConstraint("Sheet2!A:A");

		// プルダウンを設定する場所
		CellRangeAddressList region = new CellRangeAddressList(cell.getRowIndex(), cell.getRowIndex(), cell.getColumnIndex(), cell.getColumnIndex());

		DataValidation validation = helper.createValidation(constraint, region);
		sheet.addValidationData(validation);

createFormulaListConstraint()を使うと、プルダウンに表示する値をシートから取得することになる。

なお、シート名を指定する場合、そのシートは予め存在している必要がある。[2014-11-04]


ExcelのINDIRECT関数を使って以下のように指定することも出来る。[/2014-10-18]

		// プルダウンに表示する値一覧
		DataValidationConstraint constraint = helper.createFormulaListConstraint("INDIRECT(\"Sheet2!A:A\")");

古いExcel(Excel2003とか)では「シート名!A:A」といったシート名入りの範囲を入力規則に指定することが出来ないので、このようにINDIRECT関数(文字列でセル参照を指定する)を用いた形になる。

ただし「シート名入りの範囲」はExcelから入力が出来ないだけで、指定されていたらちゃんと有効になるようなので、POIで入力する分には気にしなくてよい。


なお、POI 3.10-FINALでは、設定されている入力規則を取得する方法は無いようだ。なんてこったい!

POI 3.11以降は以下の方法で取得できる。(プルリクエストしたらマージされた)[2017-02-18]

		List<? extends DataValidation> validationList = sheet.getDataValidations();
		for (DataValidation validation : validationList) {
			〜
		}

数式の解析・変更

POIでは、セルに設定された計算式(数式)を解析して他セルへの参照を取得・変更することが出来る。[2014-10-13]

POIでは、計算式の文字列を解析してPtgの配列に変換することが出来る。
Ptgは「parse thing」の略で、数式内のセル参照やその他の部分を表す。
もちろん、Ptgの配列から計算式の文字列を生成することも出来る。
セル参照用のPtg内の値を変更することにより、セル参照の内容を変更することが出来る。

Ptgを扱う方法は、(poi-3.10-FINALでは)HSSFとXSSFを透過的に扱う方法は提供されていない。
Ptgを取得するにはFormulaParsingWorkbookインターフェースの具象クラス、Ptgから文字列を生成するにはFormulaRenderingWorkbookインターフェースの具象クラスが必要となる。
HSSFではHSSFEvaluationWorkbookクラス、XSSFではXSSFEvaluationWorkbookクラスがこれらのインターフェースを実装している。


計算式の解析(Ptgの取得)

Ptgを取得するには、HSSFのみを扱うのであれば、以下の様にするのが簡単。

import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.Workbook;
	public static Ptg[] parseCellFormula(String formula, Workbook workbook) {
		Ptg[] ptgs = HSSFFormulaParser.parse(formula, (HSSFWorkbook) workbook);
		return ptgs;
	}

HSSFとXSSFを扱う場合は以下の様になる。

import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.Workbook;
		String formula = cell.getCellFormula();
		Ptg[] ptgs = parseCellFormula(formula, cell.getSheet().getWorkbook());
	public static Ptg[] parseCellFormula(String formula, Workbook workbook) {
		FormulaParsingWorkbook book;
		if (workbook instanceof HSSFWorkbook) {
			book = HSSFEvaluationWorkbook.create((HSSFWorkbook) workbook);
		} else if (workbook instanceof XSSFWorkbook) {
			book = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
		} else {
			throw new UnsupportedOperationException(workbook.getClass().getName());
		}

		Ptg[] ptgs = FormulaParser.parse(formula, book, FormulaType.CELL, -1);
		return ptgs;
	}

parseメソッドの第4引数に渡している「-1」は、シート番号。名前の解釈に使うようだが、具体的に何に使うのかはよく分からない^^;


計算式(文字列)の生成

Ptgから計算式の文字列を生成するには、以下の様にする。

import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.formula.FormulaRenderer;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.Workbook;
		String formula = toFormulaString(cell.getSheet().getWorkbook(), ptgs);
		cell.setCellFormula(formula);
	public static String toFormulaString(Workbook workbook, Ptg[] ptgs) {
		FormulaRenderingWorkbook book;
		if (workbook instanceof HSSFWorkbook) {
			book = HSSFEvaluationWorkbook.create((HSSFWorkbook) workbook);
		} else if (workbook instanceof XSSFWorkbook) {
			book = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
		} else {
			throw new UnsupportedOperationException(workbook.getClass().getName());
		}

		String formula = FormulaRenderer.toFormulaString(book, ptgs);
		return formula;
	}

セル参照を変更する例

あるシートを指している計算式(セル参照)を別シートに変更する例。

import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaRenderer;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
import org.apache.poi.ss.formula.ptg.RefPtg;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
	public static void updateFormulaSheet(Workbook workbook, int srcSheetIndex, int dstSheetIndex) {

		FormulaParsingWorkbook parseBook;
		FormulaRenderingWorkbook renderBook;
		if (workbook instanceof HSSFWorkbook) {
			HSSFEvaluationWorkbook book = HSSFEvaluationWorkbook.create((HSSFWorkbook) workbook);
			parseBook = book;
			renderBook = book;
		} else if (workbook instanceof XSSFWorkbook) {
			XSSFEvaluationWorkbook book = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
			parseBook = book;
			renderBook = book;
		} else {
			throw new UnsupportedOperationException(workbook.getClass().getName());
		}

		for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
			Sheet sheet = workbook.getSheetAt(i);
			for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {
				Row row = sheet.getRow(j);
				if (row == null) {
					continue;
				}
				for (int k = row.getFirstCellNum(); k <= row.getLastCellNum(); k++) {
					Cell cell = row.getCell(k);
					if (cell == null || cell.getCellType() != Cell.CELL_TYPE_FORMULA) {
						continue;
					}

					// 計算式を解析
					String formula = cell.getCellFormula();
					Ptg[] ptgs = FormulaParser.parse(formula, parseBook, FormulaType.CELL, -1);

					for (Ptg ptg : ptgs) {
						//「A1」形式
						if (ptg instanceof RefPtg) {
							RefPtg refptg = (RefPtg) ptg;
							System.out.printf("(row=%s%d, col=%s%d)\n",
								refptg.isRowRelative() ? "" : "$", refptg.getRow(),
								refptg.isColRelative() ? "" : "$", refptg.getColumn());
						}

						//「Sheet!A1」形式
						if (ptg instanceof Ref3DPtg) {
							Ref3DPtg ref3dptg = (Ref3DPtg) ptg;
							System.out.printf("sheetIndex=%d (row=%s%d, col=%s%d)\n",
								ref3dptg.getExternSheetIndex(),
								ref3dptg.isRowRelative() ? "" : "$", ref3dptg.getRow(),
								ref3dptg.isColRelative() ? "" : "$", ref3dptg.getColumn());

							// 別シートへの参照に変更
							if (ref3dptg.getExternSheetIndex() == srcSheetIndex) {
								ref3dptg.setExternSheetIndex(dstSheetIndex);
								//ref3dptg.setRow(0);
								//ref3dptg.setColumn(0);
							}
						}
					}

					// 計算式を文字列に変換
					String updateFormula = FormulaRenderer.toFormulaString(renderBook, ptgs);
					if (!updateFormula.equals(formula)) {
						System.out.println(updateFormula);
						cell.setCellFormula(updateFormula);
					}
				}
			}
		}
	}

泥臭く、ワークブック内の全シートの全セルを走査する。

Ptgは、計算式の解析結果に応じて色々な具象クラスになっている。
「A1」形式のセル参照はRefPtg、「シート名!A1」形式のセル参照はRef3DPtgクラスである。
それぞれのクラスに「指している先を取得するメソッド」や「値を変更するメソッド」があるので、それを使って指し先を変更することが出来る。
同様に、範囲を指定するAreaPtg・Area3DPtgというクラスがある。[2014-11-04]

クラス 数式文字列の例 主なメソッド
RefPtg A1 getRow setRow 行インデックス
getColumn setColumn 列インデックス
isRowRelative setRowRelative 行指定が相対かどうか
isColRelative setColRelative 列指定が相対かどうか
Ref3DPtg Sheet!A1 getExternSheetIndex setExternSheetIndex シート番号
getRow setRow 行インデックス
getColumn setColumn 列インデックス
isRowRelative setRowRelative 行指定が相対かどうか
isColRelative setColRelative 列指定が相対かどうか
AreaPtg A1:B2 getFirstRow setFirstRow 左上セルの行インデックス
getFirstColumn setFirstColumn 左上セルの列インデックス
isFirstRowRelative setFirstRowRelative 左上セルの行指定が相対かどうか
isFirstColRelative setFirstColRelative 左上セルの列指定が相対かどうか
getLastRow setLastRow 右下セルの行インデックス
getLastColumn setLastColumn 右下セルの列インデックス
isLastRowRelative setLastRowRelative 右下セルの行指定が相対かどうか
isLastColRelative setLastColRelative 右下セルの列指定が相対かどうか
Area3DPtg Sheet!A1:B2 getExternSheetIndex setExternSheetIndex シート番号
getFirstRow setFirstRow 左上セルの行インデックス
getFirstColumn setFirstColumn 左上セルの列インデックス
isFirstRowRelative setFirstRowRelative 左上セルの行指定が相対かどうか
isFirstColRelative setFirstColRelative 左上セルの列指定が相対かどうか
getLastRow setLastRow 右下セルの行インデックス
getLastColumn setLastColumn 右下セルの列インデックス
isLastRowRelative setLastRowRelative 右下セルの行指定が相対かどうか
isLastColRelative setLastColRelative 右下セルの列指定が相対かどうか

AreaPtgやArea3DPtgの場合、「A:A」のように列だけを指定した数式では、行インデックスは絶対指定で0と最大値(HSSFなら65535)になる。


POI目次へ戻る / Excel操作ライブラリーへ戻る / Java目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま