C言語でCSVの文字列をsscanfで読み込む方法
スポンサーリンク
このドキュメントの内容は、以下の通りです。
はじめに
CSVという言葉を耳にしたことがある方は多いのではないでしょうか?
CSV とは、カンマ セパレータ バリューのことで、それぞれの単語の頭文字からCSVと略して呼ばれています。CSVは、名前の通り、バリュー(値)が、「カンマ」で区切られて格納されたファイルのことを言います。ファイル名の拡張子は .csv です。
学校やオフィスで、CSVファイルを扱ったことがある方がいらっしゃると思います。Windows のパソコンで Office を利用されている方は Excel で、表として扱っているのではないでしょうか?CSVの親戚にTSV(タブセパレータバリュー)というタブで区切った形式のファイルもあります。
CSVやTSVは、表計算ソフトやなんらかのアプリケーションで作成されます。
CSV/TSVは、データのやりとりを受け渡しするために、よく利用されています。
CSV/TSVは、ただのテキストファイルなので、Linux/Unix などのコマンドでも扱いやすいファイルです。
CSVをExcelなどの表計算ソフトで扱う場合もあれば、プログラムで扱う場合もあります。ここでは、C言語で扱う方法について考えてみます。
時代遅れの関数について
scanf の関数は、バッファオーバーランの危険性があるため、以前より問題のある関数とされていました。 そのため、JPCERTのホームページのドキュメントでは、scanf や sscanf のような関数は、時代遅れの関数と言われています。
そして、時代遅れでない関数があります。
sscanf の場合では、 sscanf_sです。ただし、sscanf_s は、マイクロソフトの Visual Stdio (ビジュアルスタジオ)などの限られた環境でしか利用できないようです。
C言語でCSVを読む方法を考える
C言語でCSV(カンマセパレーテッドバリュー)の文字列を読み込む方法について考えます。
ここでは、CSVのファイルではなく、カンマで区切られた文字列を扱います。
CSVのファイルを扱いたい場合には、 fgets でループを回しながら、 sscanf を利用する、とといった方法が考えられます。
C言語には、データを入力するための関数として scanfが古くから利用されています。scanfは、標準入力(stdin) から受け取ります。 fscanfはファイルから入力します。sscanfは、文字列を入力として扱います。
このような文字列をsscanf関数で読み込みます。
abc,def,ghi
この例だと、うまくいきません。
#include <stdio.h> #include <stdlib.h> #define BUF 16 int main (int argc, char *argv[]) { char *str = "abc,def,ghi"; char buf1[BUF]; char buf2[BUF]; char buf3[BUF]; int r; r = sscanf (str, "%s,%s,%s", buf1, buf2, buf3); printf ("n=%d, [%s] [%s] [%s]\n", r, buf1, buf2, buf3); exit (EXIT_SUCCESS); }
下記のプログラムの場合、1つしかとれてません。
r = sscanf (str, "%s,%s,%s", buf1, buf2, buf3);
buf1 にしか、値が入っていません。
buf2, buf3 は、未初期化の影響で、メモリに入っていた謎のデータが表示されています。
% ./a.out n=1, [abc,def,ghi] [] [a(壟真☆(_(]
上記の問題は、フォーマット指定子の %sに 「, 」 (カンマ)が含まれてしまうのが原因です。
これに対して、下記のように修正をしてみます。
r = sscanf (str, "%[^,],%[^,],%[^,]", buf1, buf2, buf3);なんだか、正規表現っぽくなってきました。
サンプルのプログラムを以下のように書き直しました。
#include <stdio.h> #include <stdlib.h> #define BUF 16 int main (int argc, char *argv[]) { char *str = "abc,def,ghi"; char buf1[BUF]; char buf2[BUF]; char buf3[BUF]; int r; r = sscanf (str, "%[^,],%[^,],%[^,]", buf1, buf2, buf3); printf ("n=%d, [%s] [%s] [%s]\n", r, buf1, buf2, buf3); exit (EXIT_SUCCESS); }
これで、, (カンマ)をセパレータとして、読み込むことができます。
以下の通り、うまくいっていることが確認できました。
% ./a.out n=3, [abc] [def] [ghi]
ライブラリでCSVをパースできないのか
Python だと簡単に CSV ファイルを扱うようなライブラリがあります。
C言語ではどうでしょうか?
調べてみると libcsv といった、それっぽいライブラリが出てきます。
github に libcsv のソースコードがあり、FreeBSD には libcsv のパッケージがあります。 Ubuntu でも libcsv-dev や libcsv3 といった CSV のパーサーとライターのライブラリがあります。
sscanf でやるにも限界があると思います。sscanf は、標準ライブラリだけでお手軽にできるわけですが、バグのないコードを1から書くのも骨が折れるため、ライブラリでやったほうが良いのではないかと思います。
C言語関連の記事
[2007-12-22-1] FreeBSD C言語のerrnoの実装[2007-10-01-1] C言語でカレントディレクトリを取得する getcwdの使い方
[2007-09-23-3] C言語の_Boool型とC99とgccとstdbool.hのbool型
[2007-07-17-1] C言語による間違えトップ10
[2007-07-16-1] C言語使いのJavaScript strstr
[2007-07-02-4] Part1 オープンソース/C言語に学ぶ「ソースコードの読み方」
参照しているページ (サイト内): [2007-10-01-1]
スポンサーリンク
スポンサーリンク
いつもシェア、ありがとうございます!
もっと情報を探しませんか?
関連記事
最近の記事
- パナソニック ジェットウォッシャードルツ EW-DJ61-Wのホースの修理
- LinuxセキュリティモジュールIntegrity Policy Enforcement
- アマゾンのEcho Show 5を買ったのでレビューします
- アマゾンのサイバーマンデーはAlexa Echo Show 5が安い
- Android スマートフォン OnePlus 7T と OnePlus 7の違い
- Android スマートフォン OnePlus 7 をAndroid10にアップデートしてみた
- クレジットカードのバーチャルカードの比較のまとめ
- 活動量計 Xiaomi Mi Band 4を買ってみたのでレビュー
- Android スマートフォン OnePlus 7 のレビュー
- AliExpressでスマートフォンを買い物してみた
- パソコンのホコリ対策 レンジフードフィルターと養生テープ
- 80PLUS GOLDのPC電源ユニットAntec NeoEco 750 Goldのレビュー
- イギリスの付加価値税 VAT は払い戻しを受けられる
- イギリスのロンドンでスーツケースなど荷物を預けられる場所は
- イギリスのロンドンで地下鉄やバスに乗るならオイスターカードを使おう
- イギリスのヒースロー空港からロンドン市内への行き方
- 航空便でほかの航空会社に乗り継ぎがある場合のオンラインチェックイン
- SFC会員がANA便ではなくベトナム航空のコードシェアを試して解ったこと
- ベトナムの入国審査でeチケットの掲示が必要だった話
- シアトルの交通ICカードはオルカカード(Orca)です
人気のページ
- Windows7 IME 辞書ツールで単語の登録に失敗しました
- C言語 popen()でコマンドを実行して出力を読み込む
- Windows7で休止状態にする方法
- CentOS MySQLの起動、停止、再起動
- loggerコマンドでsyslogにエラーを出力する方法
- パソコンパーツの買取をしてくれる店のまとめ
- Java Mapの使い方 get(),put(),remove(),size(),clear()
- 楽天のRポイントカードを作ってみた
- iPhone 5 から iPhone 6 に乗り換えたのでレビュー
- netstatコマンドのステータスの意味
スポンサーリンク
過去ログ
2020 : 01 02 03 04 05 06 07 08 09 10 11 122019 : 01 02 03 04 05 06 07 08 09 10 11 12
2018 : 01 02 03 04 05 06 07 08 09 10 11 12
2017 : 01 02 03 04 05 06 07 08 09 10 11 12
2016 : 01 02 03 04 05 06 07 08 09 10 11 12
2015 : 01 02 03 04 05 06 07 08 09 10 11 12
2014 : 01 02 03 04 05 06 07 08 09 10 11 12
2013 : 01 02 03 04 05 06 07 08 09 10 11 12
2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12
2003 : 01 02 03 04 05 06 07 08 09 10 11 12