83197


言語はC#で、NPOI.SS.UserModelを使って、エクセルのセルの値を取得するプログラムを書いています。

問題なのは、formulaの書かれたセルです。C#でこのセルの計算結果を取得したいと思っていますが、うまくいきません。

エクセルの計算式は、下記のようなものです。

[code]

    =LOOKUP(CA36,{0,40,50,60,70,80,90;"Ｄ","Ｃ","Ｂ2","Ｂ1","Ａ2","Ａ1","Ｓ"})
    
[/code]

また、このセルの書式は、

[code]

    セルの書式設定 > 表示形式 > 分類=標準
    
[/code]

となっています。

この式が書かれたセルを読み込むとき、そのエクセルのまま読み込むとき①と、そのエクセルに何かしらの編集（A1セルに適当な文字列を書き込んで保存するなど）をかけたあとに読み込むとき②の挙動が違います。

②の状態に一旦した後は、該当セルの計算結果が変わるようにエクセルを編集して再度読み込ませても正しく読み込まれるようになります。

本来ならば①のときに正しい計算結果の値が取得されないといけないのですがなぜか0という数値が取得されます。②の状態にすると正しい値が読み込まれ例えば"Ｄ"という文字列が取得されます。

この挙動の違いがなぜ起こるのかが分かりません。

ちなみに、  
①のとき、

[code]

    cell.CellType==CellType.Formula
    cell.CachedFormulaResultType==CellType.Numeric
    cell.NumericCellValue=0
    
[/code]

②のとき

[code]

    cell.CellType==CellType.Formula
    cell.CachedFormulaResultType==CellType.String
    cell.StringCellValue="Ｄ"
    
[/code]

コードは下記のようになっています。

[code]

            var book = WorkbookFactory.Create(this._fileFullPath);
            
            //1枚目のシートを取得
            var sheet = book.GetSheetAt(0);
    
            int target_row_count = 50;
            int target_col_count = 100;
    
            List<CellData> cellDatas = new List<CellData>();
    
            for (int i = 0; i < target_row_count; i++)
            {
                int rowPosi = i + 1;
                for (int j = 0; j < target_col_count; j++)
                {
                    int colPosi = j + 1;
    
                    //テスト
                    if (rowPosi == 36 && colPosi == 82) {
                        Console.WriteLine("");
                    }
    
                    string value = "";
    
                    var row = sheet.GetRow(i);
                    if (row != null) {
                        ICell cell = row.GetCell(j);
                        if (cell != null) {
                            switch (cell.CellType)
                            {
                                case CellType.String:
                                    value = cell.StringCellValue;
                                    break;
                                case CellType.Numeric:
                                    value = cell.NumericCellValue.ToString();
                                    break;
                                case CellType.Boolean:
                                    value = cell.BooleanCellValue.ToString();
                                    break;
                                case CellType.Formula:
                                    switch (cell.CachedFormulaResultType) {
                                        case CellType.String:
                                            value = cell.StringCellValue;
                                            break;
                                        case CellType.Numeric:
                                            value = cell.NumericCellValue.ToString();
                                            break;
                                        case CellType.Blank:
                                            break;
                                        default:
                                            StringBuilder sb = new StringBuilder();
                                            sb.AppendLine($"セルタイプ({cell.CellType})ですが、");
                                            sb.AppendLine($"cell.CachedFormulaResultType({cell.CachedFormulaResultType})に該当する処理がありません。");
                                            throw new Exception(sb.ToString());
                                    }
                                    break;
                                case CellType.Blank:
                                    break;
                                default:
                                    throw new Exception(
                                        $"セルタイプ({cell.CellType})に該当する処理がありません。");
                            }
                            
                            CellData cellData = new CellData(
                                new CellPosition(
                                    rowPosi,
                                    colPosi),
                                value);
    
                            cellDatas.Add(cellData);
                        }
                    }
                }
            }
    
[/code]


CC BY-SA 4.0
2021-10-18T14:23:07.757
83165
2021-10-21T06:19:54.623
43941
question
c# excel
計算式(Formula)の入ったセルの結果がNPOIで正しく読み込めない


結論を言うと、エクセルファイルを作成し書き込む処理をClosedXMLからNPOIに変更したことによって解決しました。

これまでの経緯

  1. エクセルのテンプレートファイル（Tempとする）を準備。このテンプレートには、OPで説明したLookup関数が入ったセルなどが存在する。
  2. ClosedXMLで、Tempをコピーして新しいエクセルファイル（Newとする）、そのいくつかのセルに文字列を書き込む。
  3. NPOIで、Newのファイルを読み込む。Lookup関数の結果が正しく取得できない。（←ここがOPの時点）
  4. ClosedXMLで行っていた2の処理をNPOIで行うようにプログラムを変更。
  5. 新しいプログラムで、Newファイルの作成、Newファイルの読み込みを行う。Lookup関数が入ったセルの値が正しく取得できた。

ClosedXMLとNPOIが混在していた理由は、以前はClosedXML一本で読み書きの両方の処理を行っていました。ですが、読込のときにLookup関数が正しく読み込まれないという今回とは別の事象が発生していたときに、読込処理だけNPOIに変更しました。ClosedXMLではLookup関数はサポートされていないので、読み込みがうまくいかないという記事があったからです。ですが、書き込みの部分はうまくいっていたようだったので、ClosedXMLのままにしておりました。

ですが、今回の事象で、エクセルの書き込み時にもLookup関数などのサポートされていない関数が使われていた場合は、ClosedXMLでは正しくセルの結果が評価されない状態になり、読み込むときに正しい結果が読み込めないようになっていました。


CC BY-SA 4.0
2021-10-21T03:47:23.817
83197
2021-10-21T06:19:54.623
2021-10-21T06:19:54.623
3060
43941
83165
answer