![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?5a7ff87)
explodeや正規表現など、いろいろ考えたのですが、スマートな方法が見つからず、ヒントでもいただけるとありがたいです。
やりたいことは、
ABC 123 "BBB HHH" 456 789 "あい うえお" DDD
という文字列を分割して配列に入れたいのですが、 "内は1つの文字列として分割せずに取り出したいのです。
結果として、
array(
0=>"ABC",
1=>123,
2=>"BBB HHH",// 元の"があってもなくてもいい
3=>456,
4=>789
5=>"あい うえお",
6=>DDD
)
というものを得たいわけです。
単純に explode や split ではダメですし、正規表現だとどうなるのやらと。 "内の (スペース)を他のモノに置き換えて、explodeした後もとにもどす、とかでしょうか。他に何か手がありましたら、ご教示お願いします。
No.6ベストアンサー
- 回答日時:
'\' で '"' をエスケープできるパターンだとこんな感じですか。
'\' をパターンに含めるのが面倒w
あと微妙に動作が違います。
<?php
$string ='ABC 123 "BBB HHH" 456 789 "あい \\"うえお\\"" DDD';
print("$string ->\n");
preg_match_all('/[^ "]+|"[^\\\\"]*(?:\\\\"|[^"])*"/', $string, $items, PREG_SET_ORDER);
print_r($items);
ABC 123 "BBB HHH" 456 789 "あい \"うえお\"" DDD ->
Array
(
[0] => Array
(
[0] => ABC
)
[1] => Array
(
[0] => 123
)
[2] => Array
(
[0] => "BBB HHH"
)
[3] => Array
(
[0] => 456
)
[4] => Array
(
[0] => 789
)
[5] => Array
(
[0] => "あい \"うえお\""
)
[6] => Array
(
[0] => DDD
)
)
#str_getcsv() ですか。なんでもあるなPHP。
sakusaker7様、ひきつづき解答いただきありがとうございます。
すごい。パーフェクトですね。'"'の内部のエスケープされたものも問題なく取り出してくれますね。
>あと微妙に動作が違います。
というのはどういう意味なんでしょうか?
それにしても正規表現って難しい。まだまだ勉強が足りませんね。
大変勉強になりました。
ありがとうございます。
No.9
- 回答日時:
#6のお礼でのご質問に対して。
>>あと微妙に動作が違います。
>というのはどういう意味なんでしょうか?
#2 のパターンだと、"" というダブルクォートのみのパターンは受け付けませんが
#6のだと受け付けてしまいます。
マッチングがとんでもなく遅くなる可能性があるけど#2と同じ動作をするものにするか
速度を取るかで後者を選んだという次第です。はい。
なるほど。
AAA BBB "" "CCC DDD"
の場合
0=>AAA
1=>BBB
2=>""
3=>"CCC DDD"
になるっていうことなんですね。そのあたりは、もう1処理加えて、空欄は省けば問題なさそうですね。
みなさまに教えていただいた方法をそれぞれ比較してみて利用させていただこうと思います。
貴重な時間を割いてお答えいただいてありがとうございました。
No.8
- 回答日時:
おっとしまった、読み書きで開いて先頭にseekすればよかったですね
<?php
$string ='ABC 123 "BBB HHH" 456 789 "あい \"うえお\"" DDD';
$tmpfname = tempnam("/tmp", "FOO");
$handle = fopen($tmpfname, "r+");
fwrite($handle, $string);
rewind($handle);
while (($data = fgetcsv($handle, 1000, " ")) !== FALSE) {
print_r($data);
}
fclose($handle);
if(file_exists($tmpfname)) unlink($tmpfname);
?>
解答いただきありがとうございます。
たしかに、すでに実装済みのCSV関係関数を使うためにファイルに読み書きするのも手ですね。処理的にちょっとかかりそうな気もしないでもないですが、そのへん少し比較してみたいと思います。
1つの目的のためにも、いろんなアプローチがあるものですね。おもしろい。
No.7
- 回答日時:
姑息かもしれませんが、一度テンポラリに書き出してしまうのも手です。
<?php
$string ='ABC 123 "BBB HHH" 456 789 "あい \"うえお\"" DDD';
$tmpfname = tempnam("/tmp", "FOO");
$handle = fopen($tmpfname, "w");
fwrite($handle, $string);
fclose($handle);
$handle = fopen($tmpfname, "r");
while (($data = fgetcsv($handle, 1000, " ")) !== FALSE) {
print_r($data);
}
fclose($handle);
if(file_exists($tmpfname)) unlink($tmpfname);
?>
No.5
- 回答日時:
使用した事は有りませんが、以下の関数の delimiter をスペースにする事で出来るかもしれません。
str_getcsv()
http://jp.php.net/manual/ja/function.str-getcsv. …
解答いただきありがとうございます。
そんな関数もあるんですね。あまり情報がないようですが、私の手元(PHP5.2.5 XAMPP版)ではまだ実装されてないようでした。5.3、6.0系で加わるのかもしれませんね。これが実装されればベストの解になりそうですね。
ありがとうございます。
No.4
- 回答日時:
<?php
$str='ABC 123 "BBB HHH" 456 789 "あい うえお" DDD';
preg_match_all('/"[^"]+"|\s?[^"\s]+\s?/', $str, $res);
$res0 = array_map(trim, $res[0]);
var_dump($res0);
?>
$res0に解が求まります。
これで、どうでしょう?
解答いただきありがとうございます。
'"'内でエスケープされたもの(\")でも区切られてしまいました。
少し手直しすればいけそうですね。
ありがとうございます。
No.3
- 回答日時:
explodeを2段で実行するとかどうでしょうか?
<?php
$str='ABC 123 "BBB HHH" 456 789 "あい うえお" DDD';
$words=array();
$temp=explode('"',$str);
foreach($temp AS $i => $word)
{
if($i&1)$words[]=$word;
else$words=array_merge($words,explode(" ",trim($word)));
}
print_r($words);
?>
No.2
- 回答日時:
ダブルクォートはアイテムを区切る以外に使わないという前提で。
<?php
$string ='ABC 123 "BBB HHH" 456 789 "あい うえお" DDD';
preg_match_all('/[^ "]+|"[^"]+"/', $string, $items, PREG_SET_ORDER);
print_r($items);
Array
(
[0] => Array
(
[0] => ABC
)
[1] => Array
(
[0] => 123
)
[2] => Array
(
[0] => "BBB HHH"
)
[3] => Array
(
[0] => 456
)
[4] => Array
(
[0] => 789
)
[5] => Array
(
[0] => "あい うえお"
)
[6] => Array
(
[0] => DDD
)
)
CSVのダブルクォートみたいに、エスケープすれば含められるという条件だと
要手直し。
この回答への補足
いろいろ試行してみましたが、エスケープされたものを含めるのは難しいですね。
正規表現後半の部分で [^"] の部分を すべてOKだけど "のまえには \ がこなければならない、という感じでしょうか。
(?!) や (?=) など駆使しながら試してみましたが、なかなかうまくいかず。
もし暇だったらでけっこうですのでヒントいただけると幸いです。
解答いただきありがとうございます。
おお、まさにスマートなやりかたですね。
なるほど、区切りに注目するのではなく、値を抜き出す、ということですね。
エスケープがある場合にも少し正規表現を変えるだけで対応できそうですね。
ありがとうございます。
No.1
- 回答日時:
すぐに浮かぶ手抜きなやりかた
・「"」で囲まれている単語の空白を通常使わない何かの記号に置き換える
・split
・置き換えた物を再び空白に戻す。ついでに「"」を取る
「通常使わない何かの記号」をどうするかが一番の問題。
使用用途によっては「使ってはならない記号類」というのが出てくるだろうからそれを使ったら良いんじゃないかな。
解答いただきありがとうございます。
おっしゃるように、手順を踏めばできそうですね。
なかなか1発でするのは難しいですよね。
ただいろんなオプションがあるのはいいことです。参考にしたいと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(データベース) カラム上の重複を削除するクエリを教えてください 3 2022/04/12 14:11
- PHP PHPの構文で間違えが分からない 5 2022/07/11 16:38
- PHP SQLとPHPの連結方法がわからないのでアドバイスお願い致します 1 2022/07/12 12:16
- Visual Basic(VBA) Excel VBAでAA(BBB) → BBB.AA に置換したい 2 2022/10/30 13:59
- JavaScript javascriptで文字分割は、 split() などメソッド不要??? 4 2023/02/06 22:50
- Visual Basic(VBA) 【VBA】特定の文字で改行(次の行)に行きたい。 3 2022/04/11 17:20
- その他(プログラミング・Web制作) python質問 1 2023/08/14 11:54
- Visual Basic(VBA) 特定の文字を簡単な操作で半角スペースに変換するか削除したい 2 2022/11/01 10:35
- Excel(エクセル) エクセルの数式で教えてください。 2 2023/03/09 10:07
- その他(コンピューター・テクノロジー) 正規表現の置換で一部の文字列をそのまま残したい 2 2022/05/03 19:19
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
フォームで戻った際に入力済み...
-
「ログイン機能を持たせる」説...
-
PHP8を使うと、大量のWarningが...
-
ゆゆにゃ。
-
アマゾンのような評価の星を選...
-
配列の値の更新方法について
-
phpのエラーについて
-
空文字 "" ですが 空文字の意味...
-
if (!empty($_POST) ){ // フォ...
-
functionsでどこまで括るのか固...
-
こちらはただの直列処理ですか?
-
PHPでこのコード自体に意味は無...
-
PHPとHTML+Xamppの掲示板で画像...
-
オススメのプログラミングスク...
-
これの対応OSを教えて下さい。p...
-
PHPのセッション有効期限について
-
php 入力画面から確認表示画面...
-
phpでこの記述をもっと簡単に書...
-
preg_matchで Warning: Undefin...
-
jpgraphで表示されない
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
php 指定文字列以降の削除
-
^[a-zA-Z_][a-zA-Z0-9_]* でマ...
-
DIRECTORY_SEPARATORについて
-
PHPの変数で最初から2行分の文...
-
PHPの正規表現 パターン修飾子...
-
PHPでurlから第4レベルドメイン...
-
正規表現で3回目の単語の後に文...
-
正規表現で一桁の数字を二桁に...
-
メールアドレスチェックの方法
-
正規表現の「^」と「$」がうま...
-
正規表現でタグからURLを取り出...
-
PHPの正規表現で【】内を文字列...
-
フォントの色を変えるには?
-
onedrive にexcelファイルをア...
-
PHPのif文でその処理を途中で抜...
-
こちらはただの直列処理ですか?
-
別ファイルの変数を呼び出した...
-
PHP8を使うと、大量のWarningが...
-
トランザクションが原因?DBに...
-
form actionで二つ送信先を指定...
おすすめ情報