初心者です。
PHP5を始めて約50時間程度です。
テキストファイルの処理についての質問です。
fgets,file_put_contents,str_replace,array等の関数を使い処理するのだと思います。
構文が組み立てられません。
参考になるサイト等アドバイスいただけると幸いです。
よろしくお願いします。
下記の様な元になるテキストファイルがあります。
1.最初の文字があるまで(=改行だけの行)は削除
2.最初の文字列の最後に”,”を入れ改行をとる
3.次の行と次の次の行は削除
4.次の行は、例:7月4日(土)を7,4,土に
5.次の行は、例:10:00~13:00を10:00,13:00に
6.次の行と次の次の行は削除して改行
7.次の行と次の次の行は削除
8.前述1から7までの繰り返し
*最終的には後述のようなテキストファイルになります
----元になるテキストファイル
植物の光合成
理科
3
相田ももこ
7月4日(土)
10:00~13:00
30名
5,000円
鎌倉時代
社会
3
土田正
7月4日(土)
14:00~17:00
30名
5,000円
生物の進化
理科
6
長谷川浩
7月4日(土)
10:00~17:00*会場は大阪です
16名
10,000円
----元になるテキストファイル以上
---完成後のファイル
植物の光合成, 理科,7,4,土,10:00,13:00
鎌倉時代,社会,7,4,土,14:00,17:00
生物の進化,理科,7,4,土,10:00,17:00
---完成後のファイル以上
No.1
- 回答日時:
「テキスト→CSV」の変換を行いたい、ということですね。
> fgets,file_put_contents,str_replace,array等の関数を使い処理するのだと思います。
必要な関数はわかっているようですので、ポイントだけ説明します。
未検証につき細かなミスがあるかもしれませんが、考え方(アルゴリズム)だけ受け取ってください。
1. テキストファイル取得
file_get_contents で受け取り、変数に格納します。
この際、trimで前後の空行を取り除くと良いと思います。
2. 空行で区切り、配列に分割格納する
CSV変換後の1行は空行区切りのブロックと捉えて良さそうです。
split で空行(\n{2,})を区切り文字に指定して、各ブロックを配列に分割格納します。
3. preg_replace でCSV形式に変換する
2. で作成した配列を foreach で処理をループさせます。
各配列の値に対してpreg_replace を使って1行のCSVに変換し、配列の値を上書きします。
4. implodeで配列から文字列に戻す
implode で区切り文字に改行(\n)を指定して、文字列に戻します。
5. file_put_contents で書き込み
完成です。
PHP: file_get_contents - Manual
http://jp.php.net/manual/ja/function.file-get-co …
PHP: file_put_contents - Manual
http://jp.php.net/manual/ja/function.file-put-co …
PHP: trim - Manual
http://jp.php.net/manual/ja/function.trim.php
PHP: split - Manual
http://jp.php.net/manual/ja/function.split.php
PHP: foreach - Manual
http://jp.php.net/manual/ja/control-structures.f …
PHP: preg_replace - Manual
http://jp.php.net/manual/ja/function.preg-replac …
PHP: implode - Manual
http://jp.php.net/manual/ja/function.implode.php
# file_get_contentsを知っていたのに、file_put_contentsを知らなかった…。
# PHP5からの関数だから見逃していたのかな。
この回答への補足
初心者ですいません。
>3. preg_replace でCSV形式に変換する
>2. で作成した配列を foreach で処理をループさせます。
>各配列の値に対してpreg_replace を使って1行のCSVに変換し、配列の値を上書きします。
>
>4. implodeで配列から文字列に戻す
>implode で区切り文字に改行(\n)を指定して、文字列に戻します。
>
>5. file_put_contents で書き込み
>完成です。
上記3の部分でうまくいきません。
「preg_replace を使って1行のCSVに変換し」が組み立てられないのだと思います。
3,4,5の参考例文のようなもの、アドバイス、いただけると幸いです。
---私のソース
<?php
$file = file_get_contents(('test01.txt'));
//$file = preg_replace("/^(\s)*(\r|\n|\r\n)/m", "", $file);
$array = split("[\n{2,}]",$file);
foreach ($array as $key => $value) {
$array = preg_replace("/^(\s)*(\r|\n|\r\n)/m", ",", $array);;
}
print_r($array);
?>
---私のソース以上
---print_rの表示の一部
Array ( [0] => , [1] => , [2] => , [3] => , [4] => 植物の光合成 [5] => 理科 [6] => 3 [7] => 相田ももこ [8] => 7月4日(土) [9] => 10:00~13:00 [10] => 30名
---print_rの表示の一部以上
test01.txtは、最初に投稿したものと同じです。
早速参考マニュアルサイトまで書いていただきありがとうございます。
私のスキルからすると、かなり高度な事をやっているようです。
大変感謝しています。取り急ぎ御礼まで。
No.2
- 回答日時:
初心者であることを卑下することはないと思いますよ。
わからないなりに工夫して試した跡が見られるので、私は逆に向上心のある初心者さんだと思っています。
> $array = preg_replace("/^(\s)*(\r|\n|\r\n)/m", ",", $array);;
恥ずかしながら preg_replace が配列を引数に持てるということを知りませんでした。これならforeachが不要になります。
すみません、余計に混乱させてしまいましたね。
私の環境では下記コードでほぼ期待通りの結果になりました。
<?php
$file = file_get_contents('test01.txt');
$array = split("[\n{2,}]",$file);
$array = preg_replace("/(?:\r\n|[\r\n])/", ",", $array);
header('Content-Type: text/plain; charset=UTF-8');// Content-Typeヘッダ出力
print_r($array);
?>
# header() は「テキストとして扱うため + 文字コード指定で文字化けを防ぐため」です。
# 省略できるなら省略しちゃっても構いません。
この回答への補足
下記ソースを書きました。
---下記ソース
<?php
$file = file_get_contents('test01.txt');
$array = split("[\n{2,}]",$file);
$array = preg_replace("/(?:\r\n|[\r\n])/", ",", $array);
//header('Content-Type: text/plain; charset=sjis'); // Content-Typeヘッダ出力
$text_work = implode("\r\n", $array);
//echo $text_work;
file_put_contents("test02.txt","$text_work");
?>
---下記ソース以上
最終行の"test02.txt"には、最初の'test01.txt'と同ほぼじものが出力されてしまいます。
(10,000円が10改行000円改行が違うだけ)
*”各配列の値に対してpreg_replace を使って1行のCSVに変換し、配列の値を上書きします。”
→これは、出来ているのだと思います。
*”,”だけの行が削除できない。
*”円”があったら新しいテキストファイル(test02.txt)上で改行
(質問の7.次の行と次の次の行は削除)
何かアドバイスいただけると幸いです。
度々すいません。
>私は逆に向上心のある初心者さんだと思っています。
教えていただいた上に、励ましの言葉まで頂き、ありがとうございます。
深謝しています。
No.3ベストアンサー
- 回答日時:
えっと…、ごめんなさい。
改めて試したところ、#2のコードにミスがあることがわかりました。
× $array = split("[\n{2,}]",$file);
\n{2,} としなければ空行にマッチできませんし、何よりShift_JISやUTF-8だと改行は \r\n でした。
#2では \nで区切られてしまうため、CSVになるときの行単位ではなく、セル単位で配列化してしまっています。
このため、以降のコードが全て正常に動かないのです…。
余計な回り道をさせてしまって申し訳ないです。
以下にサンプルコードを作りましたので、参考にしてください。(今度は検証したので動くはずです…)
<?php
$file = file_get_contents('test01.txt');
$file = mb_convert_encoding($file, "UTF-8", "auto");// preg用にUTF-8に文字コード変換(preg系はUTF-8にすると全角文字を扱える正規表現として機能します)
/* 行単位の配列に (1次元配列) */
$array = preg_split("/(?:\r\n){2,}/m", $file);// 空行区切りで分割
/* セル単位の配列に (2次元配列) */
foreach($array as &$value){
$value = preg_split("/\r\n/", $value);// CSVのセルデータに分割 (配列の値を更に配列に。ここで2次元配列になります)
}
/* CSV形式に変換 */
foreach($array as &$value){
$value = preg_replace('/"/', '""', $value);// ダブルクオートをエスケープ
$value = preg_replace('/^.*$/', '"$0"', $value);// セルデータ全体をダブルクオートで括る
$value = implode(',', $value);// 2次元配列→1次元配列
}
$output = implode("\r\n", $array);// 1次元配列→文字列
$output = mb_convert_encoding($output, "Shift_JIS", "auto");// Shift_JIS文字コードに
header('Content-Type: text/plain; charset=Shift_JIS'); // Content-Typeヘッダ出力
echo $output;// 出力
?>
> *”,”だけの行が削除できない。
"," は区切り文字なので、値に持ちたい場合はエスケープする(安全な文字に変換する)必要がありますね。
この場合CSVを読み込むプログラムによってエスケープ方法が変わります。
念のため確認しますが、完全なCSV形式でいいのですか?
つまり、読み込むプログラムはExcelと思ってよいですか?
上のコードはExcelで読む前提で書いています。
PHPで読むなどしていて "," のエスケープ方法が特殊だとそれに準拠した形にする必要があります。
ちなみに、掲示板で使われるCSVでは改行は <br> に、"," はHTML文字実体参照にすることが多いですね。
CSVファイルフォーマットの解説:CodeZine
http://codezine.jp/article/detail/2364
> *”円”があったら新しいテキストファイル(test02.txt)上で改行
> (質問の7.次の行と次の次の行は削除)
配列にしてしまえば後は簡単です。
- 配列の値をpreg_replaceしてNULL(空データ)にする
- preg_matchでチェックしてから unset()
のいずれかで対応してください。
あと、サンプルでは省略した「セルの順番変更」ですが、2次元配列にする以前にやった方がわかりやすいと思います。
echo preg_replace('/^(\d{4})(\d{2})(\d{2})$/', '$1/$2/$3', "20090520");// 出力
こんな感じで括弧を使って必要な部分をキャプチャし、変数で並び替えてみてください。
No.4
- 回答日時:
#3の補足です。
「"," をエスケープする必要がある」と書きましたが、#3では「全データをダブルクオートで括る」形式にしています。
ダブルクオートで括ることで、「"," をエスケープする」のではなく「'"' をエスケープする」に変化します。
Excelで出力するCSVは「改行を含む」または「カンマを含む」データ限定でダブルクオートで括っていますが、
全データをダブルクオートで括ってもExcelで読み込むことが出来ます。(それでもCSVフォーマットに準拠しているので)
この回答への補足
出来ました。
ありがとうございました。
2行目と21行目に下記メッセージが出ました。
Warning: mb_convert_encoding() [function.mb-convert-encoding]: Unable to detect character encoding
$file = mb_convert_encoding($file, "UTF-8", "auto");→
$file = mb_convert_encoding($file, "UTF-8", "Shift_JIS");
header('Content-Type: text/plain; charset=Shift_JIS'); →
//header('Content-Type: text/plain; charset=Shift_JIS');
で解決しました。
教えていただいたプログラムは、一行ずつ意味を解釈し勉強してみます。
私はVB6で育った世代で、配列の概念が極めて希薄だと教えていただいた中で感じています。
*VBだと1行ずつ読んでその中で処理しworkファイルに落とす、ような感じになると思います。
重ね重ねありがとうございました。
深謝しています。
最後に完成したソースを貼っておきます。
<?php
$file = file_get_contents('test01.txt');
$file = mb_convert_encoding($file, "UTF-8", "Shift_JIS"); // preg用にUTF-8に文字コード変換(preg系はUTF-8にすると全角文字を扱える正規表現として機能します)
/* 行単位の配列に (1次元配列) */
$array = preg_split("/(?:\r\n){2,}/m", $file); // 空行区切りで分割
/* セル単位の配列に (2次元配列) */
foreach($array as &$value){
$value = preg_split("/\r\n/", $value); // CSVのセルデータに分割 (配列の値を更に配列に。ここで2次元配列になります)
}
/* CSV形式に変換 */
foreach($array as &$value){
$value = preg_replace('/"/', '""', $value); // ダブルクオートをエスケープ
$value = preg_replace('/^.*$/', '"$0"', $value); // セルデータ全体をダブルクオートで括る
$value = implode(',', $value); // 2次元配列→1次元配列
}
$output = implode("\r\n", $array); // 1次元配列→文字列
$output = mb_convert_encoding($output, "Shift_JIS", "auto"); // Shift_JIS文字コードに
//header('Content-Type: text/plain; charset=Shift_JIS'); // Content-Typeヘッダ出力
echo $output; // 出力
file_put_contents("test02.txt","$output");
?>
---完成したソース
<?php
$file = file_get_contents('test01.txt');
$file = mb_convert_encoding($file, "UTF-8", "auto"); // preg用にUTF-8に文字コード変換(preg系はUTF-8にすると全角文字を扱える正規表現として機能します)
/* 行単位の配列に (1次元配列) */
$array = preg_split("/(?:\r\n){2,}/m", $file); // 空行区切りで分割
/* セル単位の配列に (2次元配列) */
foreach($array as &$value){
$value = preg_split("/\r\n/", $value); // CSVのセルデータに分割 (配列の値を更に配列に。ここで2次元配列になります)
}
/* CSV形式に変換 */
foreach($array as &$value){
$value = preg_replace('/"/', '""', $value); // ダブルクオートをエスケープ
$value = preg_replace('/^.*$/', '"$0"', $value); // セルデータ全体をダブルクオートで括る
$value = implode(',', $value); // 2次元配列→1次元配列
}
$output = implode("\r\n", $array); // 1次元配列→文字列
$output = mb_convert_encoding($output, "Shift_JIS", "auto"); // Shift_JIS文字コードに
header('Content-Type: text/plain; charset=Shift_JIS'); // Content-Typeヘッダ出力
echo $output; // 出力
?>
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) エクセルのマクロについて教えてください。 2 2023/07/21 09:42
- Java java 次の機能を有するメソッドを自クラスに作成し、実装したいです。 機能 名前判定機能 →名前が 3 2022/06/16 16:08
- Visual Basic(VBA) エクセルのマクロについて教えてください。 1 2023/08/08 11:02
- その他(プログラミング・Web制作) awkの BEGIN{RS=""} で空行を削除できるが、削除できる仕組みが分からない。 1 2023/05/02 14:14
- Excel(エクセル) 【VBA】指定フォルダに格納中のテキストファイルをエクセルで処理し結果のエクセルを新規フォルダに保存 1 2022/03/25 14:19
- C言語・C++・C# c言語の問題です 2 2023/07/21 10:51
- Visual Basic(VBA) 列 A に同じ日が2つが必要です。 1 2023/03/28 07:25
- 小学校 小学校の授業参観って年に何回ありますか? 1 2022/08/20 21:06
- ヨーロッパ みなさん、旅行好きですか? 3 2023/02/16 12:25
- Visual Basic(VBA) 3つのプロシージャをまとめたら実行時エラー発生で対応不能 6 2022/05/17 01:47
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
PHPのカッコ[ ]の使い方について
-
$_SESSIONに二次元配列を使える...
-
postgresql関数をつかったレコ...
-
foreachのなかで次のキーを参照...
-
ファイルから指定行数分だけ読...
-
PHPで配列をPOSTデータで送った...
-
String だと「 ByRef引数の型が...
-
PHP 配列の添字に変数は使えない?
-
file_existsでファイル名の部分...
-
fgetsで取り込んだ文字をexplod...
-
PHP 多次元配列変数のデータ受...
-
配列を回すとき、最後の要素だ...
-
PHPプログラミング スペースで...
-
phpで、連想配列を普通の配列に...
-
ネストが深い時のforeachはどう...
-
CakePHPのfindの取得件数は?
-
配列のランク付け
-
エラーの原因について
-
PHPでこのコード自体に意味は無...
-
別ファイルの構造体の値を読み...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
配列をループでたくさん宣言し...
-
file_existsでファイル名の部分...
-
$_SESSIONに二次元配列を使える...
-
foreachのなかで次のキーを参照...
-
String だと「 ByRef引数の型が...
-
配列を回すとき、最後の要素だ...
-
配列一致(要素順番は違うが内容...
-
PHPのカッコ[ ]の使い方について
-
ネストが深い時のforeachはどう...
-
チェックボックス複数選択 mys...
-
PHPで配列をPOSTデータで送った...
-
phpで、連想配列を普通の配列に...
-
PHP 多次元配列変数のデータ受...
-
postgresql関数をつかったレコ...
-
【PHP】配列内のある値以上をカ...
-
SQL文の実行結果を変数で受けて...
-
プルダウンメニューでCSVデータ...
-
Smartyのテンプレートからjavas...
-
PHPにてクラスを配列にすること...
-
CSVデータのn番目だけの値を取...
おすすめ情報