◆PROCESSING 逆引きリファレンス
カテゴリー:ファイル操作
CSVデータを取り出すには
【解説】
事務系のプログラムやビジネスプログラムを作成していると、時々CSVファイルを使いたい場面に出会います。
PROCESSINGにはCSVやTSVを簡単に扱える命令と、それを扱うのに適したTableという独自のクラスが用意されています。
CSVやTSVファイルを読み込む方法については「CSVファイルを読み込むには」記事で紹介しました。
ここでは読み込んだ結果得られる Tableクラスのインスタンス変数を用いて、データを取り出す方法を幾つか紹介したいと思います。
Tableクラスには、ここで紹介した命令以外にも便利なものがありますので、詳しくは公式リファレンスを参照してください。
【構文】
以下の命令はすべて Tableクラスのメソッドです。tbl がTableクラスのインスタンス変数という前提でお読みください。
読み込んだ行数を取得する
int rowCount = tbl. getRowCount( ) ;
rowCount : CSVまたはTSVファイルの行数
読み込んだ列数を取得する
int colCount = tbl. getColumnCount( ) ;
colCount : CSVまたはTSVファイルの列数
指定した行と列で値を取り出す
String getStr = tbl. getString( int row, int column ) ;
String getStr = tbl. getString( int row, String colName ) ;
int getInt = tbl. getInt( int row, int column ) ;
int getInt = tbl. getInt( int row, String colName ) ;
float getFloat = tbl. getFloat( int row, int column ) ;
float getFloat = tbl. getFloat( int row, String colName ) ;
row : 0から始まる行位置
column : 0から始まる列位置
colName : 列名(ヘッダありモードで読み込んでいる場合だけ利用可能)
特定の文字を含む行を探す
TableRow tblRow = tbl. matchRow( String regexp, int column ) ;
TableRow tblRow = tbl. matchRow( String regexp, String colName ) ;
Iterable<TableRow> it = tbl. matchRows( String regexp, int column ) ;
Iterable<TableRow> it = tbl. matchRows( String regexp, String colName ) ;
regexp : 探したい文字列
column : 0から始まる列位置
colName : 列名(ヘッダありモードで読み込んでいる場合だけ利用可能)
tblRow : 指定した文字列を含む行インスタンス(TableRow)
it : 指定した文字列を含む行インスタンス(TableRow)のイテレータ集合
【注意】
読み込んだ行数を取得する
getRowCount( ) で、loadTable()命令で読み込んだファイルの行数を知る事が可能です。
ただしloadTable() する際にヘッダー有りを指定した場合は、ヘッダーを除く行数が戻される事に注意してください。
例えば上記のようなCSVファイルがあるとして、これを
- loadTable( “hoge.csv”, “header” ); で読み込んでいるなら1が
- loadTable( “hoge.csv” ); で読み込んでいるなら2が
戻されます。
改行だけのファイルからでも行数を得ることができます。例えば以下のように改行が1つだけあるファイルを
- loadTable( “hoge.csv”, “header” ); で読み込んでいるなら0が
- loadTable( “hoge.csv” ); で読み込んでいるなら1が
戻されます。
読み込んだ列数を取得する
getColumnCount( ) で、loadTable()命令で読み込んだファイルの列数を知る事が可能です。
上記のようなファイルなら、Number、Name、Kind、Weight の4列があるので、4が戻されます。
getRowCount( ) と同じく、改行だけしかないファイルからでも列数を得ることができます。例えば以下のように改行が1つだけあるファイルを読み込んでいる場合は、1が戻されます。
指定した行と列で値を取り出す
項目を文字列として取り出すなら getString()、整数として取り出すなら getInt()、小数値として取り出すなら getFloat()を使います。
いずれの命令も行位置、列位置は0から始まる整数です。
またデータを半角シングルクォーテーション(‘)で囲んでいる場合や、データの前後にTAB文字や空白文字を含んでいる場合は、それらも含めて取り出される事にも注意してください。
取り出したデータのシングルクォーテーションや、空白、TAB文字が不要な場合は、自分たちのプログラムで除去する工夫が必要となります。
またgetInt() や getFloat() は数値に変換できる項目を取り出す用途で利用します。数値化できない文字列(例えば上記CSVの「コリー」など)を取り出すと、getInt() では0が、getFloat() では NaN (Not a Number)が戻されます。
列位置は数値以外にも、文字列(列名)で指定する事が可能です。例えば上記の例なら、「コリー」を取り出す際に tbl. getString( 1 , ”Kind” ) ; と指定することができます。
ただし列位置を文字列で指定するには、ヘッダ有りで読み込ませている必要があります。ヘッダ無しで読み込んだファイルを列名指定で取り出そうとすると、「This table has no header. so no column titles are set」 例外が発生します。
列名の大文字小文字、TABなどの制御文字や空白文字は、すべて正確に指定する必要があります。指定した列名が見つからないと、「The table has no column named XXXX(XXXXは指定した列名)」例外が発生します。
上記例なら、tbl. getString( 1 , ”KIND” ); や tbl. getString( 1 , ” Kind” ) ; はNGという事になります。
また同じ列名が複数ある場合は、最後に見つけた(最後尾にある)列側の値が戻されます。上記のようなファイルに tbl. getString( 0 , ”種類” ); とすると、「秋田犬」が戻されます。
特定の文字を含む行を探す
読み込ませたファイルから、指定した列に特定の文字列を含むものがあるか検査して、その行全体を取り出す事が可能です。
tbl.matchRow() なら指定した文字を含む最初の行が、tbl.matchRows() なら全ての行が戻されます。
matchRow()、matchRows() 共に、戻されるのはTableRowクラスのインスタンスで、該当インスタンスには見つけた「行全体」の情報が含まれています。
例えば上記のようなCSVファイルに対し tbl.matchRow( “秋田*”, 2 ) ; と指定すると、2列目(種類の列)に「秋田」で始まるデータがあるか探して、最初に見つけた行(0行目の情報)が戻されす。
tbl.matchRows( “秋田*”, 2 ) ; なら、0行目と3行目の情報がイテレータとして戻されます。イテレータからは、Forループを用いることでTableRowの各情報を順次取り出すことが可能です。
探したい文字列には正規表現が使えるようですが、指定されたデータが見つからないと「NUll Pointer Exception」例外が発生するため、この命令を使う場合は適切な例外処理が必須となります。
【関連記事】
サンプルプログラム
以下のサンプルでは、下記のようなCSVファイル(TestCsv.csv)がdataフォルダ配下に格納されており、ヘッダー有りで読み込んでいる事が前提です。文字コードはUTF-8が前提です。
- 1行目の「ジョン」はシングルクォーテーション付きです。
- 2行目の「ショコラ」はTAB文字付きです。
- 3行目の「武蔵」は前後に全角SPACEを含んでいます。
CSVの行数と列数を取得する例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Table tbl = null; String fileName = "TestCsv.csv"; void setup(){ //ヘッダ有りでCSVファイルを読む tbl = loadTable( fileName, "header" ); if( tbl != null ){ //正常に読めたら、行数と列数を表示する println( "行数は" + tbl.getRowCount() + "です。" ); println( "列数は" + tbl.getColumnCount() + "です。" ); } else{ //読み込み失敗 println( fileName + "の読み込みに失敗" ); } noLoop(); } void draw(){ } |
上記ファイルの行数と列数を表示します。
<出力サンプル>
ファイルが読み込めた場合
ファイルが読み込めない場合
指定した行と列位置で値を取り出す例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Table tbl = null; String fileName = "TestCsv.csv"; void setup(){ tbl = loadTable( fileName, "header" ); if( tbl != null ){ //正常に読めたら、各行から1列目を取り出す for( int row = 0; row < tbl.getRowCount(); row++ ){ try { //列が取り出せた println( row+"行目の犬の名前:[" + tbl.getString( row, 1 ) +"]" ); } catch( Exception e ){ //列が取り出せない println( "列取り出し異常:" + e.getMessage() ); } } } noLoop(); } void draw(){ } |
上記ファイルから1列目のデータ(Name列)を列番号で取得しています。各値の取り出され方に注意してください。
「ジョン」にはシングルクォーテーションが付いています。「ショコラ」の前にはTAB文字が付いています。「武蔵」の前後には全角SPACEが付いています。
指定した行と列名で値を取り出す例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Table tbl = null; String fileName = "TestCsv.csv"; final String COL_KIND = "Name"; void setup(){ ヘッダ有りでCSVファイルを読む tbl = loadTable( fileName, "header" ); if( tbl != null ){ //正常に読めたら、各行から1列目を取り出す for( int row = 0; row < tbl.getRowCount(); row++ ){ try { //列が取り出せた println( row+"行目の犬の名前:[" + tbl.getString( row,COL_KIND ) +"]" ); } catch( Exception e ){ //列が取り出せない println( "列取り出し異常:" + e.getMessage() ); } } } noLoop(); } void draw(){ } |
先程とほとんど同じですが、1列目のデータ(Name列)を列名で取得しています。
指定した行と列を数値として取り出す例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
Table tbl = null; String fileName = "TestCsv.csv"; void setup(){ //ヘッダ有りでCSVファイルを読む tbl = loadTable( fileName, "header" ); if( tbl != null ){ try { //正常に読めたら、全行のNumberとWeight列(0列目と3列目) //を取り出す for( int row = 0; row < tbl.getRowCount(); row++ ){ int num = tbl.getInt( row, 0 ); float weight = tbl.getFloat( row, 3 ); //getFloat()で数値化できない項目を取り出すとNaNになります。 //NaNは if( weight == Float.NaN ){ //などと比較してはいけません。 if( Float.isNaN( weight) == false ){ println( nf(num,2)+":"+tbl.getString(row,1)+ "の重さは"+ String.valueOf(weight)); } } } catch( Exception e ){ //列が取り出せない println( "列取り出し異常:" + e.getMessage() ); } } noLoop(); } |
犬の番号(0列目)と体重(3列目)を数値として取り出しています。
getFloat() で数値化できない項目を取り出すと NaN が戻されるので、(この例のCSVでは問題ないのですが)万が一の事を考えて対策を施してあります。
NaNがどうか調べるのに、if( weight == Float.NaN ){ などと比較して聞いてはいけません。例にあるように Float.isNaN() か、Double.isNaN() で調べてください。
指定した文字を含む最初の行を取り出す例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Table tbl = null; String fileName = "TestCsv.csv"; void setup(){ //ヘッダ有りでCSVファイルを読む tbl = loadTable( fileName, "header" ); if( tbl != null ){ try { //正常に読めたら、Kind(2列目)が"秋"で始まるものを探す TableRow row = tbl.matchRow( "秋", 2 ); println( "秋で始まる犬種の名前は[" + row.getString(1) + "]です" ); } catch( Exception e ){ //列が取り出せない println( "列取り出し異常:" + e.getMessage() ); } } noLoop(); } void draw(){ } |
2列目(Kindの列)が “秋” で始まる行を探し、最初に見つけた行から犬の名前(1列目)を取り出して表示しています。
指定した文字を含む全部の行を取り出す例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
Table tbl = null; String fileName = "TestCsv.csv"; void setup(){ //ヘッダ有りでCSVファイルを読む tbl = loadTable( fileName, "header" ); if( tbl != null ){ try { //正常に読めたら、犬種(2列目)が"秋"で始まるものを //全行表示する for (TableRow row : tbl.matchRows("秋", 2 )) { //取得データの前後から余計なものを取り除く String name = row.getString(1).replace(" ",""); name = name.replace("'",""); name = name.replace("\t",""); println( "秋で始まる犬種の名前は[" + name + "]です" ); } } catch( Exception e ){ //列が取り出せない println( "列取り出し異常:" + e.getMessage() ); } } noLoop(); } void draw(){ } |
先ほどと同様に2列目(Kindの列)が “秋” で始まる行を探していますが、今度は matchRows() を利用しています。
matchRows()は TableRowのイテレータを戻すので、Forループで順次取得します。
ついでに、取り出されたデータの前後から全角SPACE、シングルクォーテーション、TAB文字を取り除いて表示させています。
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。