質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

3回答

10281閲覧

文字列に「,」を含むcsvファイルをstr_getcsvで読み込むとうまく動かない

mizutama72

総合スコア31

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2018/09/05 05:29

phpで、以下のコードで、csvのヘッダー行と項目数が異なる場合はエラーとしているのですが、

php

1foreach ($lines as $key => $line) { 2 $line_count = count(str_getcsv($line)); 3  //$headerLineNumはヘッダー行項目数 4 if ($line_count != $headerLineNum) { 5 return 'ヘッダー行と項目数が異なります。'; 6 } 7} 8

以下のデータの場合、sgr_getcsvが正しく動かず、項目数を6としてしまいます。
".,",データ2,データ3,データ4,データ5

ちなみに、以下の場合は、正しく機能し、項目数が5となります。
データ2,".,",データ3,データ4,データ5

先頭にダブルクォーテーションで囲まれたものがある場合、何かしら処理が必要なのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

php

1<?php 2$input = '".,",データ2,データ3,データ4,データ5'; 3$result = str_getcsv($input); 4print_r($result); 5?> 6
Array ( [0] => ., [1] => データ2 [2] => データ3 [3] => データ4 [4] => データ5 )

あれ?上手くいきますけど。。。
データにゴミでも入っているんですかね?文字コードとか?
PHP 5.4.16 で試しました。

追記(まとめ)

つまりstr_getcsvを普通の使い方をして、

"デ"ータ1,データ2

こういうデータがあった時に
エンクロージャが外れて

データ1
データ2

こう解釈されるのはおかしいのでは?

という疑問ですよね。

確かにおかしい気はしますが、おかしいのはデータであって、
ではどう解釈するのが正しいかというのも微妙で
csvのフォーマットは歴史的に方言が沢山あるのが実情ですから
「PHPの実装はこういうものだ」と理解するのがよいかと個人的には思いました。

どうしてもこの余計な解釈を回避したい場合には、
データをcsvフォーマットとしてふさわしいものに修正変更するか、
getcsvをあきらめて自前でパースするしかなさそうです。

投稿2018/09/05 07:22

編集2018/09/05 10:07
taka-saan

総合スコア665

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mizutama72

2018/09/05 07:33

回答ありがとうございます。 本当ですね。。 私もプログラムの中で、$line = '".,",データ2,データ3,データ4,データ5';としたら、うまくいきました。 ファイルの場合だけ、おかしくなるようです。
taka-saan

2018/09/05 08:11 編集

ファイルの場合というわけではなく、おそらく、いずれかのカラムの文字が壊れている(マルチバイト文字なのに2byte目以降が無いとか、バイナリが混入しているとか)のが原因ではないでしょうか。 もしそうなら、行($line)の状態でその様な文字を捨てるか置換するなど加工して回避してから、 getcsvするのが解決法だと思います。 エラーになる行を特定して、実データのファイル上でその行を(場合によってはバイナリエディタ等で)よく調べてみてください。
mizutama72

2018/09/05 08:58

回答ありがとうございます。 頂いた回答で、色々さかのぼって調べてみました。 各行を読み込むforeachの前にcsvファイル自体を読み込んでいる部分がありまして、 $lines = str_getcsv($fileContent, "\n",'"'); どうやらこれを実行すると、おかしくなっているようでした。 ユーザのCSVファイルはサイズが大きいのでエラーになった箇所だけをコピーして1行だけのファイルを作り、 ----------------- フィールド1,フィールド2,フィールド3,フィールド4,フィールド5 ".,",データ2,データ3,データ4,データ5 ----------------- として、上記のCSVファイルを、$lines = str_getcsv($fileContent, "\n",'"');で実行すると、 $linesの結果が、 array ( 0 => 'フィールド1,フィールド2,フィールド3,フィールド4,フィールド5', 1 => '.,,データ2,データ3,データ4,データ5', ) となってしまい、ダブルクォーテーションが外れていました。 なぜ外れてしまうのかは、また謎なのですが・・・。 ちなみに、ファイルの内容を、 --------------------- フィールド1,フィールド2,フィールド3,フィールド4,フィールド5 データ2,".,",データ3,データ4,データ5 --------------------- とすると、 [2018-09-05 17:53:58] local.DEBUG: array ( 0 => 'フィールド1,フィールド2,フィールド3,フィールド4,フィールド5', 1 => 'データ2,".,",データ3,データ4,データ5', ) のように、ダブルクォーテーションが外れません。
taka-saan

2018/09/05 09:29

なるほど。 > なぜ外れてしまうのかは、また謎なのですが・・・。 $lines = str_getcsv($fileContent, "\n",'"'); この処理でエンクロージャであるダブルクォーテーションは外れますよ。 改行をデリミタとした大きなcsvにみなしてるわけですから。 「ちなみに」の方はカラムの先頭がエンクロージャでないので はずれないのは当然です。1行が1カラムとして扱ってるんですから。 こうしたらきっと直ります。 $lines = str_getcsv($fileContent, "\n",''); しかし、行を分割するのにstr_getcsv()を用いたのが失敗でしたね。 fgets()を使って1行ずつ読み込みながら$linesに追加していくのが一般的で その方が多少処理効率も良いです。 謎が分かってすっきりしました^^
taka-saan

2018/09/05 09:47

勝手にまとめます。 つまりstr_getcsvを普通の使い方をして、 "デ"ータ1,データ2 こういうデータがあった時に エンクロージャが外れて データ1 データ2 こう解釈されるのはおかしいのでは? という疑問ですよね。 確かにおかしい気はしますが、おかしいのはデータであって、 ではどう解釈するのが正しいかというのも微妙で csvのフォーマットは歴史的に方言が沢山あるのが実情ですから 「PHPの実装はこういうものだ」と理解するのがよいかと個人的には思いました。
mizutama72

2018/09/05 10:44

ご連絡が遅くなりました。 動きました!! fgetsに変更しましたら、無事に反応するようになりました。 >$lines = str_getcsv($fileContent, "\n",'"'); >この処理でエンクロージャであるダブルクォーテーションは外れますよ。 >改行をデリミタとした大きなcsvにみなしてるわけですから。 >「ちなみに」の方はカラムの先頭がエンクロージャでないので >はずれないのは当然です。1行が1カラムとして扱ってるんですから。 そうなのですね。。 よくわからず使っていました。 本当にありがとうございます。助かりました。
guest

0

第2引数以降の設定でダメなら、裏技的なことかも知れませんが、$lineの中身を加工して、str_getcsv()で正常に処理できるようにする必要があるかも知れません。
≪案1≫
ダブルクォーテーションで囲まれた要素を別の文字に置き換え、列データに分割後に元のデータに戻す。
≪案2≫
ダブルクォーテーションで囲まれた要素以外のすべての要素をダブルクォーテーションで囲むように加工する。
(これが本来のCSVの書式だが、str_getcsv()の第2引数以降の設定が必要かどうかは不明)
※元々ダブルクォーテーションで囲まれている要素は、正規表現などで検出します。

投稿2018/09/05 07:08

編集2018/09/05 07:09
kenshirou

総合スコア772

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mizutama72

2018/09/05 07:18

ご回答ありがとうございます。 案2を実際にデータでダブルクォーテーションで囲んでみましたが、結果は変わらずでした。 案1で考えてみようと思います。
kenshirou

2018/09/05 08:15

後は、他の方も指摘されているように、何か変な文字が入ってしまっているのか、データ破損が考えられます。 ところで、str_getcsv()で得られた各項目の内容はどうなっていますか?
guest

0

str_getcsv()の第2、第3引数で対応するか、CSVのデータ自体を調整する必要があると思います。
実データの内容にもよりますので、質問者さんの方で色々と調整してみてください。

投稿2018/09/05 05:46

m.ts10806

総合スコア80850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mizutama72

2018/09/05 06:49

ご回答ありがとうございます。 CSVデータはユーザのファイルのため、毎回どのようなCSVデータが渡されるのかがわからないので、CSV側の調整が難しいです。。 第2引数には「,」、第3引数に「"」を入れてみましたが、結果は変わらずでした。
m.ts10806

2018/09/05 07:04

,に"だとデフォルトと同じなので変わらなそうです。 考えられる手段としてはその関数通す前に該当文字列を置換しておいて後で元に戻すとかですが、他の箇所に囲み文字として"が入っていた場合に不具合となりそうですし。 そもそも実際はなぜそのようなデータが入ってくるんでしょう?
mizutama72

2018/09/05 07:17

分析系のシステムなのですが、今回のCSVファイルは、文章にどう行った文字が含まれた場合、分析したい他のデータにどう関係してくるのか、といったことをやっているため、上記のような記号が含まれたデータが入ってくるのだと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問