1 package jp.satomichan.nucalgen;
4 import java.io.FileInputStream;
5 import java.io.FileOutputStream;
6 import java.util.ArrayList;
8 import java.util.Map.Entry;
9 import java.util.regex.Matcher;
11 import org.apache.commons.cli.CommandLine;
12 import org.apache.commons.cli.CommandLineParser;
13 import org.apache.commons.cli.DefaultParser;
14 import org.apache.commons.cli.Option;
15 import org.apache.commons.cli.Options;
16 import org.apache.commons.lang.StringUtils;
17 import org.apache.poi.ss.usermodel.Cell;
18 import org.apache.poi.ss.usermodel.Row;
19 import org.apache.poi.ss.usermodel.Sheet;
20 import org.apache.poi.ss.usermodel.Workbook;
21 import org.apache.poi.ss.usermodel.WorkbookFactory;
22 import org.apache.poi.ss.util.CellRangeAddress;
23 import org.apache.poi.ss.util.CellReference;
25 import jp.satomichan.nucalgen.addition.AcCell;
26 import jp.satomichan.nucalgen.addition.AcRow;
27 import jp.satomichan.nucalgen.addition.AdditionConfig;
28 import jp.satomichan.nucalgen.addition.AdditionUtil;
30 public class Nucalgen {
31 //開始位置 最初の食品の、最初の栄養成分の位置 (E4セル)
32 private static final int ROW_INDEX_START = 3;
33 private static final int COL_INDEX_START = 4;
35 public static void main(String[] args) {
37 Options options = new Options();
38 options.addOption(Option.builder("s").required().hasArg().longOpt("std-food-comp-table").build());
39 options.addOption(Option.builder("c").required().hasArg().longOpt("columns").build());
40 options.addOption(Option.builder("o").required().hasArg().longOpt("output").build());
41 options.addOption(Option.builder("l").required().hasArg().longOpt("lines").build());
42 options.addOption(Option.builder("add").hasArgs().longOpt("addition").build());
43 options.addOption(Option.builder("sheets").hasArgs().build());
44 options.addOption(Option.builder("bright").hasArg().longOpt("bright-colored-vegetables-list").build());
45 options.addOption(Option.builder("protect").longOpt("set-protect").build());
46 options.addOption(Option.builder("processed").longOpt("use-processed-table").build());
48 NamedAreaStore namedArea = NamedAreaStore.getInstance();
53 CommandLineParser parser = new DefaultParser();
54 CommandLine cmd = parser.parse(options, args);
55 final String mextStdFoodCompTableFileName = cmd.getOptionValue("std-food-comp-table");
56 final String columnsXmlFileName = cmd.getOptionValue("columns");
57 final String outputXlsxFileName = cmd.getOptionValue("output");
58 final int lines = Integer.parseInt(cmd.getOptionValue("lines"));
61 NutritionColumnHolder nch = new NutritionColumnHolder(columnsXmlFileName);
64 Workbook outputWorkbook = WorkbookFactory.create(new FileInputStream(mextStdFoodCompTableFileName));
66 if(cmd.hasOption("use-processed-table") == false) {
68 MextStdFoodCompTable stdCompTable = new MextStdFoodCompTable(cmd.getOptionValue("bright-colored-vegetables-list"));
69 stdCompTable.processInto(outputWorkbook);
74 CellStylePool csPool = new CellStylePool(outputWorkbook);
75 List<String> usedTableList = new ArrayList<String>();
76 List<String> sheetNameList = new ArrayList<String>();
79 String[] sheets = cmd.getOptionValues("sheets");
80 if(sheets != null && sheets.length >= 2) {
82 for(int si = 0; si < sheets.length - 1; si++) {
83 final String sheetName = sheets[si];
84 generateCalculationSheet(outputWorkbook, sheetName, namedArea, cmd.hasOption("set-protect"), cmd.getOptionValues("addition"), lines, nch, csPool, usedTableList);
85 outputWorkbook.setSheetOrder(sheetName, si);
86 sheetNameList.add(sheetName);
88 final String sumSheetName = sheets[sheets.length - 1];
89 generateSumSheet(outputWorkbook, sumSheetName, sheetNameList, namedArea, cmd.hasOption("set-protect"), cmd.getOptionValues("addition"), lines, nch, csPool, usedTableList);
90 outputWorkbook.setSheetOrder(sumSheetName, sheets.length - 1);
94 final String sheetName = (sheets != null) ? sheets[0] : "栄養価計算";
95 generateCalculationSheet(outputWorkbook, sheetName, namedArea, cmd.hasOption("set-protect"), cmd.getOptionValues("addition"), lines, nch, csPool, usedTableList);
96 outputWorkbook.setSheetOrder(sheetName, 0);
97 sheetNameList.add(sheetName);
102 for(int si = outputWorkbook.getNumberOfSheets() - 1 ; si >= 1 ; si--) {
103 String sheetName = outputWorkbook.getSheetName(si);
104 boolean used = false;
105 for(String usedTable : usedTableList) {
106 if(usedTable.equals(sheetName)) {
111 outputWorkbook.removeSheetAt(si);
116 FileOutputStream outputXlsxFile = new FileOutputStream(outputXlsxFileName);
117 outputWorkbook.setActiveSheet(0);
119 outputWorkbook.setSelectedTab(0);
120 outputWorkbook.write(outputXlsxFile);
121 outputWorkbook.close();
123 } catch (Exception e) {
124 // TODO 自動生成された catch ブロック
137 private static void generateCalculationSheet(Workbook book, String sheetName, NamedAreaStore namedArea, boolean setProtect,
138 String[] additionOptionValues, final int lines,
139 NutritionColumnHolder nch, CellStylePool csPool, List<String> usedTableList) {
142 Sheet calcSheet = book.createSheet(sheetName);
145 calcSheet.protectSheet("");
147 calcSheet.setColumnWidth(COL_INDEX_START -2, 10240); //C「食品名」列
148 calcSheet.addMergedRegion(new CellRangeAddress(ROW_INDEX_START -2, ROW_INDEX_START -1,
149 COL_INDEX_START -3, COL_INDEX_START -3)); //B2:B3「食品番号」セル
153 Row titleRow = calcSheet.createRow(ROW_INDEX_START -2);
154 titleRow.createCell(COL_INDEX_START -3).setCellValue("食品番号");
155 titleRow.createCell(COL_INDEX_START -2).setCellValue("食品名");
156 titleRow.createCell(COL_INDEX_START -1).setCellValue("摂取量");
157 int colIndex = COL_INDEX_START;
158 for(NutritionColumn aColumn : nch.getNutritionColumnList()) {
159 titleRow.createCell(colIndex).setCellValue(aColumn.getDispName());
164 Row unitRow = calcSheet.createRow(ROW_INDEX_START -1);
165 unitRow.createCell(COL_INDEX_START -2).setCellValue("単位");
166 unitRow.createCell(COL_INDEX_START -1).setCellValue("g");
167 colIndex = COL_INDEX_START;
168 for(NutritionColumn aColumn : nch.getNutritionColumnList()) {
169 unitRow.createCell(colIndex).setCellValue(aColumn.getUnit());
174 int rowIndex = ROW_INDEX_START;
175 for(int i = rowIndex; i < lines + ROW_INDEX_START; i++,rowIndex++) {
176 Row thisRow = calcSheet.createRow(rowIndex);
179 thisRow.createCell(COL_INDEX_START -3).setCellStyle(csPool.getCellStyle("00000", false));
180 thisRow.createCell(COL_INDEX_START -2).setCellFormula("IFERROR(VLOOKUP(B" + (rowIndex + 1) +
181 ",成分表!$B$13:$BL$2500,3,FALSE),\"\")");
182 thisRow.createCell(COL_INDEX_START -1).setCellStyle(csPool.getCellStyle("", false));
184 colIndex = COL_INDEX_START;
185 for(NutritionColumn aColumn : nch.getNutritionColumnList()) {
186 Cell thisCell = thisRow.createCell(colIndex);
187 thisCell.setCellStyle(csPool.getCellStyle(aColumn.getFormat()));
189 if(aColumn.getFormula().length() >= 1) {
191 String formula = aColumn.getFormula();
192 for(String aAlias : nch.getNutritionAliasList()) {
193 formula = replaceFormula(formula, aAlias, rowIndex, COL_INDEX_START + nch.indexOf(aAlias));
195 thisCell.setCellFormula(formula);
200 String div100 = aColumn.isUseRawValue() ? "" : "/ 100 * $D" + (rowIndex + 1);
201 thisCell.setCellFormula("IFERROR(VLOOKUP($B" + (rowIndex + 1) + "," + aColumn.getTable() +
202 "!$B$13:$BL$2500,MATCH(\"" + aColumn.getName() + "\"," +
203 aColumn.getTable() + "!$B$12:$BL$12,0),FALSE) " + div100 + ",\"\")");
208 usedTableList.add(aColumn.getTable());
209 usedTableList.add(sheetName);
216 namedArea.save("AREA_INTAKE", ROW_INDEX_START, COL_INDEX_START -1, rowIndex -1, COL_INDEX_START -1);
220 Row sumRow = calcSheet.createRow(rowIndex);
221 sumRow.createCell(COL_INDEX_START -3).setCellValue("合計");
222 calcSheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, COL_INDEX_START -3, COL_INDEX_START -2));
225 Cell intakeSumCell = sumRow.createCell(COL_INDEX_START -1);
226 intakeSumCell.setCellFormula("SUM(" + namedArea.load("AREA_INTAKE") + ")");
227 namedArea.save("SUM_INTAKE", intakeSumCell);
229 colIndex = COL_INDEX_START;
230 for(NutritionColumn aColumn : nch.getNutritionColumnList()) {
231 Cell thisCell = sumRow.createCell(colIndex);
234 String areaName = aColumn.getAlias().length() >= 1 ? ("AREA_" + aColumn.getAlias()) : ("AREAID_" + aColumn.getName());
235 namedArea.save(areaName, ROW_INDEX_START, colIndex, rowIndex -1, colIndex);
237 if(aColumn.isUseSum()) {
238 String sumName = aColumn.getAlias().length() >= 1 ? ("SUM_" + aColumn.getAlias()) : ("SUMID_" + aColumn.getName());
239 namedArea.save(sumName, thisCell);
242 thisCell.setCellStyle(csPool.getCellStyle(aColumn.getFormat()));
243 if(aColumn.isUseSum()) {
244 thisCell.setCellFormula("SUM(" +
245 NamedAreaStore.getAreaString(ROW_INDEX_START, colIndex, rowIndex -1, colIndex) +
253 if(additionOptionValues != null) {
254 for(String aAdditionFileName : additionOptionValues) {
256 rowIndex = generateAddition(aAdditionFileName, calcSheet, null, csPool, rowIndex, namedArea);
260 calcSheet.setForceFormulaRecalculation(true);
269 private static void generateSumSheet(Workbook book, String sheetName, List<String> sheetNameList, NamedAreaStore namedArea, boolean setProtect,
270 String[] additionOptionValues, final int lines,
271 NutritionColumnHolder nch, CellStylePool csPool, List<String> usedTableList) {
273 usedTableList.add(sheetName);
274 Sheet sheet = book.createSheet(sheetName);
277 sheet.protectSheet("");
281 sheet.setColumnWidth(COL_INDEX_START -2, 10240); //C
282 sheet.addMergedRegion(new CellRangeAddress(ROW_INDEX_START -2, ROW_INDEX_START -1,
283 COL_INDEX_START -3, COL_INDEX_START -2)); //B2:C3「表」セル
287 Row titleRow = sheet.createRow(ROW_INDEX_START -2);
288 titleRow.createCell(COL_INDEX_START -3).setCellValue("表");
289 titleRow.createCell(COL_INDEX_START -1).setCellValue("摂取量");
290 int colIndex = COL_INDEX_START;
291 for(NutritionColumn aColumn : nch.getNutritionColumnList()) {
292 titleRow.createCell(colIndex).setCellValue(aColumn.getDispName());
297 Row unitRow = sheet.createRow(ROW_INDEX_START -1);
298 unitRow.createCell(COL_INDEX_START -2).setCellValue("単位");
299 unitRow.createCell(COL_INDEX_START -1).setCellValue("g");
300 colIndex = COL_INDEX_START;
301 for(NutritionColumn aColumn : nch.getNutritionColumnList()) {
302 unitRow.createCell(colIndex).setCellValue(aColumn.getUnit());
307 int rowIndex = ROW_INDEX_START;
308 for(String aSheetName : sheetNameList) {
309 Row thisRow = sheet.createRow(rowIndex);
311 sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex,
312 COL_INDEX_START -3, COL_INDEX_START -2)); //B:C「表」セル
315 thisRow.createCell(COL_INDEX_START -3).setCellValue(aSheetName);
318 thisRow.createCell(COL_INDEX_START -1).setCellFormula(aSheetName + "!" + namedArea.load("SUM_INTAKE"));
322 colIndex = COL_INDEX_START;
323 for(NutritionColumn aColumn : nch.getNutritionColumnList()) {
324 Cell thisCell = thisRow.createCell(colIndex);
325 thisCell.setCellStyle(csPool.getCellStyle(aColumn.getFormat()));
326 if(aColumn.isUseSum()) {
327 String sumName = aColumn.getAlias().length() >= 1 ? ("SUM_" + aColumn.getAlias()) : ("SUMID_" + aColumn.getName());
328 String formula = aSheetName + "!" + namedArea.load(sumName);
329 thisCell.setCellFormula(formula);
341 namedArea.save("AREA_INTAKE", ROW_INDEX_START, COL_INDEX_START -1, rowIndex -1, COL_INDEX_START -1);
344 Row sumRow = sheet.createRow(rowIndex);
345 sumRow.createCell(COL_INDEX_START -3).setCellValue("合計");
346 sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, COL_INDEX_START -3, COL_INDEX_START -2));
348 Cell intakeSumCell = sumRow.createCell(COL_INDEX_START -1);
349 intakeSumCell.setCellFormula("SUM(" + namedArea.load("AREA_INTAKE") + ")");
352 colIndex = COL_INDEX_START;
353 for(NutritionColumn aColumn : nch.getNutritionColumnList()) {
354 Cell thisCell = sumRow.createCell(colIndex);
357 String areaName = aColumn.getAlias().length() >= 1 ? ("AREA_" + aColumn.getAlias()) : ("AREAID_" + aColumn.getName());
358 namedArea.save(areaName, ROW_INDEX_START, colIndex, rowIndex -1, colIndex);
360 if(aColumn.isUseSum()) {
361 String sumName = aColumn.getAlias().length() >= 1 ? ("SUM_" + aColumn.getAlias()) : ("SUMID_" + aColumn.getName());
362 namedArea.save(sumName, thisCell);
366 thisCell.setCellStyle(csPool.getCellStyle(aColumn.getFormat()));
367 if(aColumn.isUseSum()) {
368 thisCell.setCellFormula("SUM(" +
369 NamedAreaStore.getAreaString(ROW_INDEX_START, colIndex, rowIndex -1, colIndex) +
377 if(additionOptionValues != null) {
378 for(String aAdditionFileName : additionOptionValues) {
380 rowIndex = generateAddition(aAdditionFileName, sheet, sheetNameList, csPool, rowIndex, namedArea);
384 sheet.setForceFormulaRecalculation(true);
392 private static int generateAddition(String fileName, Sheet calcSheet, List<String> sheetNameList, CellStylePool csPool, int rowIndex,
393 NamedAreaStore namedArea) {
395 AdditionConfig ac = AdditionUtil.additionFileReader(new File(fileName));
397 for(AcRow acRow : ac.getRows()) { //行ごとのループ
398 Row thisRow = calcSheet.createRow(rowIndex);
401 for(AcCell acCell : acRow.getCells()) { //セルごとのループ
402 Cell thisCell = thisRow.createCell(colIndex);
405 if(sheetNameList == null) {
406 String areaName = "ADDITION_" + fileName + "_" + cellCounter;
407 namedArea.save(areaName, rowIndex, colIndex);
410 //alias 「付加行」内の別名定義(制約:右方・下方のセルからしか参照できない)
411 if(acCell.getAlias() != null) {
412 namedArea.save(acCell.getAlias(), rowIndex, colIndex);
416 if(acCell.getFormula() != null){
417 String formula = acCell.getFormula();
419 if(sheetNameList != null && formula.indexOf("AREA_") != -1) {
420 //集計シート && 名前付き範囲 AREA_ が対象に含まれる
421 List<String> sumTarget = new ArrayList<String>();
422 for(String aSheetName : sheetNameList) {
423 String areaName = "ADDITION_" + fileName + "_" + cellCounter;
424 sumTarget.add(aSheetName + "!" + namedArea.load(areaName));
426 formula = "SUM(" + StringUtils.join(sumTarget, ",") + ")";
430 for(Entry<String, String> keyValue : namedArea.entrySet()) {
431 String k = keyValue.getKey();
432 String v = keyValue.getValue();
434 formula = replaceFormula(formula, k, v);
437 thisCell.setCellFormula(formula);
440 } else if(acCell.getValue() != null) {
441 thisCell.setCellValue(acCell.getValue());
443 //formula でも value でもない
463 private static String replaceFormula(String formula, String target, String replacement) {
464 formula = "<" + formula + ">";
465 replacement = Matcher.quoteReplacement(replacement);
466 formula = formula.replaceAll("([^A-Za-z0-9_])" + target + "([^A-Za-z0-9_])", "$1" + replacement + "$2");
467 formula = formula.replaceAll("^<", "");
468 formula = formula.replaceAll(">$", "");
472 //計算式中の 文字列(名前付き範囲)→セル座標 置換
473 private static String replaceFormula(String formula, String target, int cellRow, int cellCol) {
474 return replaceFormula(formula, target, new CellReference(cellRow, cellCol).formatAsString());