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

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

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

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

PHP

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

Q&A

解決済

2回答

416閲覧

TSVで読み込んだデータにデリミタになり得る文字が複数種含まれている場合の扱い方

wkbiz

総合スコア152

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

PHP

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

0グッド

0クリップ

投稿2018/11/11 16:42

編集2018/11/12 18:44

よろしくお願いします。

旧データのTSVファイルを読み込み、DBのテーブルに新テーブルへ
INSERT、UPDATEする処理を作っています。

下記はPHP公式サイトのサンプルコードを少し弄ったものですが
書いているコードはほぼコレです。

php

1<?php 2$row = 1; 3if (($handle = fopen("data.tsv", "r")) !== FALSE) { 4 while (($data = fgetcsv($handle, "", "\t", '"', ",")) !== FALSE) { 5 $num = count($data); 6 echo "<p> $num fields in line $row: <br /></p>\n"; 7 $row++; 8 for ($c=0; $c < $num; $c++) { 9 echo $data[$c] . "<br />\n"; 10 } 11 } 12 fclose($handle); 13} 14?>

ちなみに旧データはこのようになっています
<\t>はTAB区切りを表しています

id<\t>name<\t>address 100<\t>Ando<\t>Tokyo 200<\t>Kawai<\t>kawai.kazuo,kyoko<\t>jiro/hitomi@example.com ...

問題のあるデータレコードは
,"/'@\t といったデリミタとして利用される文字がほぼ全て入っています。

1レコードの特定カラムはダブルコーテーションで囲んでいますが、
どうもダブルコーテーションの中も判定しているようで、fgetcsvで
エスケープ指定している文字以外では区切りと判断してしまっています。

旧データには手を加えたくないのですが、こうも複数種のデリミタ文字が
含まれているとどうエスケープ処理させてよいのか分からず困っています。

非常に初歩的なもだと思い恐縮ですが、ご助言など頂けると幸いです。

よろしくお願いします。

#追記 頂いたご質問について。
上記のTSV例はイメージを掴んでいただくためのサンプルですので
実際扱ってるものと異なってしまうのですが、
例えばID=200のレコードの場合、
200  Kawai kawai
kazuo kyoko jiro
hitomi
example.com
のような感じで返ってきてしまいます。

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

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

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

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

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

momon-ga

2018/11/12 02:39

エスケープ指定している文字以外では区切りと判断してしまっています。について、データと戻り値が、どのようになるか追記してもらえないでしょうか。
wkbiz

2018/11/12 18:45

分かり辛いかもしれませんが、追記させて頂きました。
guest

回答2

0

うーーん。PHPのバージョンかなぁ。
提示されてるソースと、データをとりあえず実施してみましたが。再現しませんでした。

HTMLタグが入って、見ずらいですがソースそのままなので・・・

<p> 3 fields in line 1: <br /></p>

id<br />
name<br />
address<br />

<p> 3 fields in line 2: <br /></p> 100<br /> Ando<br /> Tokyo<br /> <p> 4 fields in line 3: <br /></p> 200<br /> Kawai<br /> kawai.kazuo,kyoko<br /> jiro/hitomi@example.com<br /> <p> 1 fields in line 4: <br /></p> ...<br />

ちなみに、エスケープはデリミタの直前に置くことで
デリミタを無効するための文字なので、エスケープを複数登録するものじゃないです。

追記

のような感じで返ってきてしまいます。

これは、提示されてるソース、データで実際に再現されたものでしょうか?
改行位置がずれているのも気になります。
それとも、元のソース・データで起こった事象を説明したものでしょうか?

前者であれば、環境の問題だと思われます。(私の環境では再現しないので)
後者であれば、ただしい情報を提示してもらわないと解決しないかと。

投稿2018/11/13 01:17

編集2018/11/14 01:29
momon-ga

総合スコア4820

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

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

phpsyoshinsya

2018/11/13 18:42

実際に出てきたエラーメッセージを教えてもらえますか? また、今回のソースではMYSQLを利用していますが、お使いのレンタルサーバーやローカル環境にMYSqLの設定はされていますか? postgresqlを使用する場合には、コードを書き換える必要があります。 また既にテーブルは作成されていますか?
phpsyoshinsya

2018/11/14 07:12

もしかして、私ではなく、質問者さんのコードの話ですか?
momon-ga

2018/11/14 07:23

そうです。phpsyoshinsyaさんのコメントは、コメントする場所まちがえたんかなと思っていたのですが・・・私のコードでエラーが発生したと思っていたのですね。エラーがでてるわけでなく、普通に分割できてますよーという回答をしています。
phpsyoshinsya

2018/11/14 07:36

これはまた早とちりでした。私もソースを提示していたので、それを実証実験されたのかと思い、慌ててしまいました。それと、今タグを見直したのですが、質問者さんはPOSTGRESQLですね。したがって私のコードは削除した方がいいでしょうか?
guest

0

ベストアンサー

以前に同じようなことをしたので、ぴったりのサンプルソースがありました。

fgetsはファイルから1行取得し開業またはEOFまで読み込みます。

explodeはデリミタで分割して配列で代入します。
preg_matchは"をエスケープするのに使います。
$i++がちょっと無理だったかなあと思うので、もしエラーを吐いたら$i=$i+1に修正してください。

もとファイルは"のくくりはなかったですが、そしてcsv形式でしたがそちらの元データの形にあわせたつもりです。

以下コードです。

#!/usr/local/bin/php53 <?php mb_internal_encoding("SJIS"); $db = new mysqli("localhost", "username", "password", "dbname"); $db -> set_charset("SJIS"); $fp = fopen("songs_info.txt", "r"); while($line = fgets($fp)){ $data = explode("\t", $line); for($i = 0;$i++;$i <= 5){ preg_match('/\"(.+)\"/', $data[$i], $str_match); $row[$i] = $str_match[1]; } $db -> query("insert into songs_list (song_title, singer, song_file, lyrics_url, mood, mood_id) values('{$row[0]}', '{$row[1]}', '{$row[2]}', '{$row[3]}', '{$row[4]}', '{$row[5]}') "); if($db -> error) print(" title " . $data[0] . "の登録が失敗しました:" . $db -> error . "<br>"); } fclose($fp); $result = $db -> query("select * from songs_list"); while($row = $result -> fetch_assoc()){ print($row[reg_num] . "<br>" . $row[song_title] . "<br>" . $row[singer] . "<br>" . $row[song_file] . "<br>" . $row[lyrics_url] . "<br>" . $row[mood] . "<br>" . $row[mood_id] . "<br><br>"); } $result -> close(); $db -> close(); ?>

いきなりデータベースに書き込むのが怖ければ

printf("%s,%s,%s,%s,%s,%s<br>",$row[0],$row[1],$row[2],$row[3],$row[4],$row[5]);

のようにしてみてください。

投稿2018/11/12 03:03

編集2018/11/12 03:17
phpsyoshinsya

総合スコア156

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

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

wkbiz

2018/11/12 18:34

早速ご教授いただき有難うございます。 別件優先する作業あるためまだ試していませんが参考させて頂きます。 週内または週明けごろ結果等々コメントさせて頂きます。
phpsyoshinsya

2018/11/12 19:20

取り急ぎのコメントありがとうございます。。 もしexplodeの行でエラーになるようなら "\t" としてみてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問