private Unit Read_Cost_Unit(ExcelWorksheet sheet, int start_row, Regex div_total, PartType partType)
        {
            int    row  = start_row;
            int    col  = UNIT_NAME_COLSPAN_START_COLUMN_INDEX;
            string cell = readcell_safe(sheet, row, col);
            Match  m    = regUnitName.Match(cell);

            if (!m.Success)
            {
                ExcelParseException ex = new ExcelParseException();
                ex.ExcelRow = row;
                ex.ExcelCol = col;
                ex.Hint     = "유닛 이름은 (1) 처럼 괄호 안의 숫자로 시작해야 하는데, 그러한 문자열을 찾을 수 없습니다.";
                throw new ApplicationException(ex.ToString(), ex);
            }

            Unit unit = new Unit();

            unit.name_in_excel     = cell;
            unit.name_justified    = m.Groups[m.Groups.Count - 1].Value;
            unit.vendor_totalprice = readcell_decimal_safe(sheet, row, (int)ExcelColumns.금액);

            row++;
            PartGroup pg = new PartGroup();

            while (row <= MaxRowCount)
            {
                cell = readcell_safe(sheet, row, col);
                m    = div_total.Match(cell);
                if (m.Success)
                {
                    // division ended
                    break;
                }

                m = regUnitName.Match(cell);
                if (m.Success)
                {
                    // new unit started
                    break;
                }

                ReviewPartInfo rpi = ReadVendorPart(sheet, row);
                rpi.parttype = partType;
                pg.ReviewPartInfos.Add(rpi);
                row++;
            }
            unit.partGroups.Add(pg);

            //
            CurrentWorkingRowIndex = row;
            return(unit);
        }
        private int ReadPartGroup(ExcelWorksheet sheet, int start_row, Unit unit)
        {
            int       row = start_row;
            PartGroup pg  = new PartGroup();

            while (row <= MaxRowCount)
            {
                ReviewPartInfo rpi = ReadVendorPart(sheet, row);
                {
                    // check if 구매품
                    Match m = reg구매품소계.Match(rpi.no);
                    if (m.Success)
                    {
                        pg.name              = rpi.no;
                        pg.PartGroupType     = PartType.구매품;
                        pg.vendor_totalprice = rpi.vendor_totalprice;

                        foreach (ReviewPartInfo item in pg.ReviewPartInfos)
                        {
                            item.parttype = PartType.구매품;
                        }

                        unit.partGroups.Add(pg);
                        break;
                    }
                }

                {
                    // check if 가공품
                    Match m = reg가공품소계.Match(rpi.no);
                    if (m.Success)
                    {
                        pg.name              = rpi.no;
                        pg.PartGroupType     = PartType.가공품;
                        pg.vendor_totalprice = rpi.vendor_totalprice;

                        foreach (ReviewPartInfo item in pg.ReviewPartInfos)
                        {
                            item.parttype = PartType.가공품;
                        }

                        unit.partGroups.Add(pg);
                        break;
                    }
                }

                pg.ReviewPartInfos.Add(rpi);
                row++;
            }
            return(row);
        }