🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
CSV

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

PHP

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

Q&A

解決済

2回答

9179閲覧

csvファイルのセル内のカンマを削除する方法を知りたい

k.t.est

総合スコア49

CSV

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

PHP

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

0グッド

1クリップ

投稿2021/01/27 09:20

編集2021/01/28 02:28

エクセルを利用して、下記のようなcsvファイルデータを作成して、
A列のセル内に含まれるカンマをプログラム内で削除する処理を行いたいのですが、どのようにすればよいでしょうか?
A列のセルに必ずカンマが含まれているかは不明という前提で、hoge.csvファイル自体には変更を加えないでカンマを削除したい次第です。
ご教示のほど、どうぞよろしくお願い申し上げます。

data

1//hoge.csv 2 3//csvデータはA列からK列まであり、A列以外にもカンマが含まれている列があったり、値がブランクのセルもランダムにある前提です。 4 5A1セル : 1,000いろは|12000 6B1セル : aaa 7C1セル... 8 9A2セル : 2000にほへ|100 10B2セル : bbb 11C2セル.... 12 13A3セル : 300とちり|1000 14B3セル : ccc 15C3セル.... 16 17A4セル : 4,000ぬるを|200 18B4セル : ddd 19C4セル.... 20

csv読み込み用に作成したプログラムは下記です。

php

1ini_set('auto_detect_line_endings',true); 2$strFilePath = "./"; 3$strFileName = 'hoge.csv'; 4 5//-------------------------------------------------- 6// 文字コードを変換した一時ファイルの作成 7//-------------------------------------------------- 8// ファイルの読み込み 9$data = file_get_contents($strFilePath. $strFileName); 10// 文字コードの変換(UTF-8 → SJIS-win) 11$data = mb_convert_encoding($data, 'UTF-8', 'SJIS-win'); 12// 一時ファイルの作成 13$temp = tmpfile(); 14// メタデータからファイルパスを取得して読み込み 15$meta = stream_get_meta_data($temp); 16// 一時ファイル書き込み 17fwrite($temp, $data); 18// ファイルポインタの位置を先頭に 19rewind($temp); 20 21//-------------------------------------------------- 22// ファイルの読み込み 23//-------------------------------------------------- 24// CSVファイルの読み込み 25$objFile = new SplFileObject($meta['uri'], 'rb'); 26$objFile->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY); 27$objFile->setCsvControl("\t"); 28 29//-------------------------------------------------- 30// データの取得 31//-------------------------------------------------- 32 33$list = []; 34foreach ($objFile as $row){ 35 //Aセル内のカンマを削除したものを$listに格納したい 36 var_dump($row); 37 exit(); 38 /* $row[0]に1行分のデータがカンマ区切りで格納されている状態です。 39 * array(1) { 40 * [0] => string(xxx) "1,000いろは|12000,aaa,....." 41 * } 42 */ 43}

###csvデータをテキストエディタで読み込んだ場合

csv

1//カンマが入っているセルデータにはダブルクォテーションが入っていました。 2 31行目 : "1,000いろは|12000",aaa,..... 42行目 : 2000にほへ|100,bbb,...... 53行目 : 300とちり|1000,ccc,..... 64行目 : "4,000ぬるを|200",ddd,..... 7

#追加で判明したこと
試しに、A列の前に一列足してみたところ、2番目の行データからカンマが含まれているとforeach内の$row[0]内でダブルクォーテーションで囲まれることがわかりました。
先頭行の場合は、カンマが含まれていてもダブルクォテーションでは囲まれませんでした。

一方、テキストエディタで読み込んだ場合は、先頭行かどうかに関わらず、カンマがあるデータはダブルクォテーションで囲まれていました。

####先頭行のセルデータにカンマがある場合

php

1 2foreach ($objFile as $row){ 3 var_dump($row); 4 exit(); 5 /* $row[0]に1行分のデータがカンマ区切りで格納されている状態です。 6 * array(1) { 7 * [0] => string(xxx) "1,000いろは|12000,aaa,....." 8 * } 9 */ 10} 11

先頭行以外のセルデータ内にカンマがある場合

php

1 2foreach ($objFile as $row){ 3 var_dump($row); 4 exit(); 5 /* 1,000いろは|12000がダブルクォーテーションで囲まれている。 6 * array(1) { 7 * [0] => string(xxx) "100番目,"1,000いろは|12000",aaa,....." 8 * } 9 */ 10}

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

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

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

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

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

m.ts10806

2021/01/27 09:37

foreachでループされている$rowにどのように情報がおさめられているか確認すれば明白ではないでしょうか。
k.t.est

2021/01/28 01:43

ご指摘ありがとう御座います。$rowのデータを事前に明記して質問をするべきで御座いました。 $row[0]に1行分のデータがカンマ区切りで格納されている為、どのようにすればA行のセル内にカンマが含まれていた場合でも正しくA行だけのデータを取り出せるのかがわからない次第で御座いました。 ($row[0]のデータを見るだけでは、どこまでがA行のセルデータかがわからなかった次第です。)
guest

回答2

0

ベストアンサー

$objFileにファイルから読み込んだ全行のデータが入っていて、
それをforeachループよって1行分ずつ$rowで処理するっていう流れになているのは理解できますか?

1つの行データ$row
1つ目のデータが$row[0]
2つ目のデータが$row[1]にと分割されて納められているのだから、
PHP: str_replace - Manual
を使って、
$row[0] = str_replace(',', '', $row[0]); などとすれば「,」を探して「」にする、
つまりカンマ文字を削除するという意味になります。

文字列の置換処理については類似のものとして
PHP: preg_replace - Manualもありますが、
正規表現による高度で複雑な処理向けのものなので、今はstr_replace()が無難です。

置き換え処理後に
$list[] = $row;
とでもすれば配列$listの最後尾に追加されたりするわけで、
foreachループの終わりに $list[] = $row; を置くことで、
1行分のデータを逐一処理して全行分処理する繰り返し処理になります。


/* $row[0]に1行分のデータがカンマ区切りで格納されている状態です。

  • array(1) {
  • [0] => string(xxx) "1,000いろは|12000,aaa,....."
  • }

*/

という様子から察すると、CSVファイルとして想定するフォーマットになってないために、
機械的な分割処理ができてない状況だろうと思います。

php

1$objFile = new SplFileObject($meta['uri'], 'rb'); 2$objFile->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY); 3$objFile->setCsvControl("\t");

の様子から察するに、CSVというよりもTSVなのですね?
タブで区切られているときの分割にはいいですが、「,」で区切られているときは $objFile->setCsvControl("\t"); が余計なコードになってます。
でもファイルではタブでは区切られておらず、「,」で区切られているから分割できていないのです。

じゃぁ$objFile->setCsvControl("\t");の行を削除すればいいかというと、
おそらく「,」を検出して機械的に分割してしまうため、
それも都合悪い話なのでしょう。

「,」が1つ目にしか現れないという前提なら、
まず $objFile->setCsvControl("\t"); の行を削除して、
こんなコードを足したらどうでしょう。

php

1<?php 2 3$csv_string = '1,000いろは|12000,aaa,bbb,ccc'; // 4つのセルがあると仮定する 4$cells = explode(',', $csv_string); 5if (count($cells) > 4) { // 4つより多いと検出→1つ目と2つ目を再結合させる 6 $cells[1] = $cells[0] . ',' . $cells[1]; 7 array_shift($cells); 8} 9print_r($cells);

結果は

Array
(
[0] => 1,000いろは|12000
[1] => aaa
[2] => bbb
[3] => ccc
)

となりますが、このやり方は1箇所の決まったセルでのみ余計に分割されるときにしか対応できません。


余計な分割を防げるよう「"」で囲ってあるデータなら、
$objFile->setCsvControl("\t"); の行だけ削除でいけます!

投稿2021/01/27 10:03

編集2021/01/28 02:41
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

k.t.est

2021/01/28 01:46 編集

ご回答ありがとうございます。 質問内のforeachのループ内でvar_dumpした内容を追記させていただきました。 $rowのデータ構造がなぜか異なっておりまして、$row[0]に行内の全てのセルデータがカンマ区切りで格納されておりまして、その為A行のデータのみを取り出すことができずというもので御座います。 このようなcsvファイルデータの場合はどのように対応するのがよいのでしょうか?ご教示くださいますと誠にありがたく存じます。
退会済みユーザー

退会済みユーザー

2021/01/28 02:01

想定するCSV形式になっていないために、分割に失敗しているようです。 単にテキストエディタで読み込んだときの冒頭の数行を掲載していただけませんか、質問文中に。
k.t.est

2021/01/28 02:33

追加のご回答ありがとう御座います。 しかしながら、読み込みデータにおいて、A列のデータだけでなく、どこのセルデータにカンマが含まれるかどうかがわからない為、ご教示いただいた方法が使えない次第で御座います。。。
退会済みユーザー

退会済みユーザー

2021/01/28 02:35

ダブルクォーテーションマークがついているなら、私が追記したコードは不要で、 $objFile->setCsvControl("\t"); だけ取っ払えばいいです。
k.t.est

2021/01/28 02:42

ありがとうございます。 おっしゃられる通り、$objFile->setCsvControl("\t");を削除したところ、$rowの配列がセルデータ毎に分割されました!
guest

0

fgetcsvで読んで、再帰処理で変更すればよいでしょう

php

1array_walk_recursive($csv,function(&$x){ 2 $x=str_replace(",","",$x); 3}); 4print_r($csv);

投稿2021/01/28 00:35

編集2021/01/28 00:42
yambejp

総合スコア116688

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

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

k.t.est

2021/01/28 01:57

ご回答ありがとう御座います。 皆様のご回答を拝見して、そもそものcsvデータが少し特殊なものという気がして参りました。 $row[0]に行内全てのデータがカンマ区切りで入ってしまっている為、A行のみのデータを取り出すのが難しい次第で御座います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問