Spreadsheet::ParseExcelでlinuxのperlからexcelファイルを読む - end0tknr's kipple - 新web写経開発
Mike Blackwell / Spreadsheet-XLSX - search.cpan.org
Douglas Wilson / Spreadsheet-ParseExcel - search.cpan.org
python用 xlsx module は、openpyxl と xlrd の2種類
www.python-excel.org には、 xlrd は xls用と記載されていますが、xlrdも xlsxを読めるようです。
ただ、後述するように数式による値を算出できない場合もあるようですので openpyxl がよいと思います。
openpyxl - A Python library to read/write Excel 2010 xlsx/xlsm files — openpyxl 2.4.9 documentation
xlrd documentation — xlrd 1.1.0 documentation
xlrd/openpyxl for python と Spreadsheet::XLSX/Spreadsheet::ParseExcel for perl の相違点
今回、気づいた範囲では、 数式のあるcellの値を参照した際の返り値が異なっていました。
lang | module | method | 値or数式 |
---|---|---|---|
perl | Spreadsheet::XLSX | $cell->value() | 値 |
perl | Spreadsheet::ParseExcel | $cell->value() | 値 ※1 |
python | xlrd | cell.value | 値 ※2 |
python | openpyxl | cell.value | 数式or値 ※3 |
※1 2017/9/3時点のSpreadsheet::ParseExcelのdocumentを読むと TODOに「Add Formula support」と記載されていました。
※2 後日、xlrd を試していたら、SUM()の値を取得できず、 0となることがありました。
※3 load_workbook(xlsx_path, data_only=True) で開くと、数式でなく値を取得できます
xlrd for python の sample script
#!/usr/local/bin/python # -*- coding: utf-8 -*- import getopt import sys import xlrd def main(): xlsx_path = sys.argv[1] wbook = xlrd.open_workbook(xlsx_path) for sheet_name in wbook.sheet_names(): print '## SHEET_NAME=' + sheet_name wsheet = wbook.sheet_by_name(sheet_name) for row in range(wsheet.nrows): for col in range(wsheet.ncols): cell = wsheet.cell(row,col) val = cell.value if val == None: continue print "(%d,%d)=%s" % (row,col,val) if __name__ == '__main__': main()
↑こう書くと↓こう表示されます
## SHEET_NAME=Sheet1 (0,0)=1.0 (0,1)=2.0 (0,2)=3.0 (1,0)=4.0 (1,1)=5.0 (1,2)=6.0 (2,0)=5.0 (2,1)=7.0 (2,2)=9.0
openpyxl for python の sample script
数式がそのまま表示されることが分かります
#!/usr/local/bin/python # -*- coding: utf-8 -*- from openpyxl import load_workbook import getopt import sys def main(): xlsx_path = sys.argv[1] wbook = load_workbook(xlsx_path) for sheet_name in wbook.get_sheet_names(): print '## SHEET_NAME=' + sheet_name wsheet = wbook.get_sheet_by_name(sheet_name) row = wsheet.min_row row_max = wsheet.max_row col_min = wsheet.min_column col_max = wsheet.max_column while row <= row_max: col = col_min while col <= col_max: cell = wsheet.cell(row=row,column=col) val = cell.value if val == None: col += 1 continue val_2 = cell.internal_value print "(%d,%d)=%s,%s" % (row,col,val,val_2) col += 1 row += 1 if __name__ == '__main__': main()
↑こう書くと↓こう表示されます
## SHEET_NAME=Sheet1 (1,1)=1,1 (1,2)=2,2 (1,3)=3,3 (2,1)=4,4 (2,2)=5,5 (2,3)=6,6 (3,1)==SUM(A1:A2),=SUM(A1:A2) (3,2)==SUM(B1:B2),=SUM(B1:B2) (3,3)==SUM(C1:C2),=SUM(C1:C2)
Spreadsheet::XLSX for perl の sample script
#!/usr/local/bin/perl use strict; use warnings; use Encode; use Spreadsheet::XLSX; use Data::Dumper; main(@ARGV); sub main { my ($xlsx_path) = @_; my $wbook = Spreadsheet::XLSX->new($xlsx_path); for my $wsheet (@{$wbook -> {Worksheet}}) { print "## SHEET_NAME= $wsheet->{Name}\n"; my $row = $wsheet->{MinRow}; my $row_max = $wsheet->{MaxRow}; my $col_min = $wsheet->{MinCol}; my $col_max = $wsheet->{MaxCol}; print "RANGE=$row,$row_max,$col_min,$col_max\n"; while($row<=$row_max) { my $col = $col_min; while($col<=$col_max) { my $cell = $wsheet->{Cells}[$row][$col]; if(not $cell){ $col += 1; next; } my $val = $cell->value(); my $val_2 = $cell->unformatted(); print "($row,$col)=$val , $val_2\n"; $col += 1; } $row += 1; } } }
↑こう書くと↓こう表示されます
## SHEET_NAME= Sheet1 RANGE=0,2,0,2 (0,0)=1 , 1 (0,1)=2 , 2 (0,2)=3 , 3 (1,0)=4 , 4 (1,1)=5 , 5 (1,2)=6 , 6 (2,0)=5 , 5 (2,1)=7 , 7 (2,2)=9 , 9