• ベストアンサー

&(半角アンド)が含まれる文字列の分割

http://oshiete1.goo.ne.jp/kotaeru.php3?q=644082 質問したものです。 &が%26なのはわかったのですが、それを分割する術がわかりません。 ただ普通にsplitでやってしまうと意図しない&で切れてしまいます。 どのようにしたらいいですか?

質問者が選んだベストアンサー

  • ベストアンサー
  • Ethersky
  • ベストアンサー率71% (168/235)
回答No.2

URLデコード前に&を使って分けましょう。 そして連想配列(ハッシュ)に突っ込みましょう。 で、煮るなり焼くなりした方がいいです。(というかそれが普通です) 見たところ、遠回りなことやってますよ。 read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); foreach $pair (split(/&/,$buffer)){ ($name,$value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $FORM{$name} = $value; } それと、配列なのに > @filew = "$TITLETITLE=$TITLE&$DATETITLE=$DATE&……\n"; とやっている意味が不明です。 これなら普通に変数に代入するべき。 で、使いまわさないなら print FH "$TITLETITLE=$TITLE&$DATETITLE=$DATE&……\n"; とやった方がメモリを無駄に消費せずに済みます。 最後に、日本語が混ざったりするならjcode.plなりJcode.pmに通した方が身のためですよ。(ぉ)

KODAMAR
質問者

お礼

回答ありがとうございます。 read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); $buffer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; foreach $pair (split(/&/,$buffer)){ ($name,$value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $FORM{$name} = $value; } この方法は使ってました。 というかこれでやろうと思ったのですができなくて、今みたいな方法をとってみたんですが(苦し紛れに) 上記の方法でやると、 $NAKAMI =~ /^(.*?)=(.*)$/;$NAKAMITITLE = $1;$NAKAMI = $2; のやり方がわからないんです。 こういうことをやるためにはどうしたらいいのですか? foreachの中に $FORM{$name} =~ /^(.*?)=(.*)$/;$name = $1;$value = $2; とやってみましたがダメでした。

その他の回答 (5)

  • estea
  • ベストアンサー率44% (39/87)
回答No.6

require '../jcode.pl'; read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); foreach $pair (split(/&/,$buffer)){ ($name,$value) = split(/=/, $pair,2); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $FORM{$name} = $value; } でかまいません。 jcode をrequire しているのに処理が書かれていませんが :P >この方法は間違っているでしょうか? 動いているなら問題ありません(ぉ ただ、form から送られる場合、普通 split の第三引数は必要ありません。 なぜなら formデータ中の = は %xx 形式のままだからです。だからこそsplit 下後の、代入直前で $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; を行って = に戻しています。同様に & もここで戻されます。 split 第三引数が持ち出された理由は split するより前に $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; していたことか、 $bugffer='a=b&c=d=e' のような代入をスクリプト内で行っていたためです。 ただし、以上は form からの入力の場合です。アンカーなどで自分で引数を組み立てた場合はURLエンコードのタイミングがブラウザのそれとずれるかもしれませんので、それぞれに考える必要はあります。

KODAMAR
質問者

お礼

すいません、無事できました。 こちらの勘違いでした。

KODAMAR
質問者

補足

回答ありがとうございます。 なんとか無事できそうです…と思っていたらまた問題発生です…。 ---------------------------------------- ふつう  41~60 少し悪い 21~40 最悪    1~20 とメッセージを出すプログラムを書いてみたいと思います。 If n = 2 Then MsgBox "チョキを出しました" End If と単独の条件は、やりましたね。 If文では、And 演算子 Or 演算子 を使用して、複数の条件を書くことが出来ます。 簡単に書くと、 If 評価する男性 = 金持ち And 評価する男性 = カッコイイ then と書くと、男性が金持ちで なおかつ 男性がカッコイイ両方の条件を満たす時、 If 給料 = 高い Or 場所 = 近い then と書くと、給料が高い か 場所が近い時 どちらかの条件がOKの時です。 ふざけてないで、真面目に解説しろ?って、 話を戻して、 1から100の乱数を発生させ、今日の運勢 最高   81~100 と表示なので、 数値が81より大きく、100より小さい時なので、 If 乱数 >= 81 And 乱数 <= 100 then If n >= 81 And n <= 100 then となります。 ---------------------------------------- という文章を打っていたとします。 (とあるメルマガからの抜粋です。) すると上記の例の下から3行目の「If 乱数 」までで切れて、 「= 81 And 乱数 <=~」から下が表示されてしまいます。 入力は正常に行えています。別のフォームから見たときは表示もきちんとされています。 ただ、searchという形をとった時のみ、切れてしまいます。 どこが原因なのでしょうか?

回答No.5

蛇足かもしれませんがいくつかアドバイスを。 ログファイルにデータが出なかった理由ですが、 $ENV{'CONTENT_LENGTH'} が小文字になっているからです。 (Perlは変数名の大文字と小文字を別物として扱うため) あとはログの方にもデータが現れると思いますが、 途中で経過を出力するなりして受け渡しを研究してみてください。 一点気をつけることとしては、 ($TITLE,$DATE,$NAKAMI,$WORD,$TIME,$SEARCHKEY)=split(/&/,$buffer,6); の部分ですが、 受け取ったデータが必ずしも title, date, nakami word … の順に並んでるとは限りません。 IEではformタグの順番通りに来るようですが、 それでもaction=postが先頭に来ると思います (正式な規格などは存じ上げませんが) 結論としては、どんな順序で受け取ってもかまわないように 受け取る側でプログラムしておくのが大事かと思います。 (それもあってハッシュを通常使います。  もちろん、効率の面もありますが)

KODAMAR
質問者

お礼

回答ありがとうございます。 >$ENV{'CONTENT_LENGTH'} >が小文字になっているからです。 しりませんでした。気をつけます。 >受け取ったデータが必ずしも >title, date, nakami word … >の順に並んでるとは限りません。 >IEではformタグの順番通りに来るようですが、 >それでもaction=postが先頭に来ると思います 是も知りませんでした。 例えば相手のブラウザがIEではない場合、意図しない動きをするってことですよね? ありがとうございました

KODAMAR
質問者

補足

ここに書かせていただきますが、 =の件については無事解決しました。 read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); $buffer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; foreach $pair (split(/&/,$buffer)){ ($name,$value) = split(/=/, $pair,2); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $FORM{$name} = $value; と、splitの部分で「2」と指定してやることでのりきれました。 やはり&が残ってしまいました。。。 どのようにしたらいいのでしょうか?

  • estea
  • ベストアンサー率44% (39/87)
回答No.4

ごめん。 偉そうに言って間違ってる。 name の + もスペースに戻すべきかもしれんし jcode.pl も第一引数は \$value のほうがよさそう 文字コードは euc のほうがよさそうだし

KODAMAR
質問者

補足

すいません、かくところがなくて、ここに書かせていただきます。 #5の回答の補足よりもこちらの方が最新です。 ~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; として、=や&を最初に文字にしてしまうから分割されるんであって、最初に分割してから文字にすれば…という考えにいきつきまして…。 それで以下のように変更してみました。 require '../jcode.pl'; read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); #$buffer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; foreach $pair (split(/&/,$buffer)){ ($name,$value) = split(/=/, $pair,2); $value =~ tr/+/ /; #$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $FORM{$name} = $value; $FORM{$name} =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; } 一応表示は無事できました。 この方法は間違っているでしょうか? 私はまた何か危ないことをやらかそうとしてるのでしょうか?(^^; もしこれで何か今後不都合が予想されるなどありましたら教えてください。

  • estea
  • ベストアンサー率44% (39/87)
回答No.3

えっと、前の 「=でうまく切れない」 でお尋ねの splitの 第三引数ですが、ココで指定された引数個以上に分割しないってことです。 $buf = 'a=b=c=d'; のとき split(/=/,$buf,2) すれば返る配列は ('a' , 'b=c=d') です。 GETやPOSTを受け取る方法は、流儀はあるとは思いますが結構普通に使われているコードは、以下のようなのだと思います。 #reqire 'jcode.pl'; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } foreach $pair (split(/&/,$buffer)) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; #&jcode'convert(*value,'sjis'); #日本語使うなら。 $FORM->{$name} = $value; } 他にこういった部分では、タグの無効化とかファイルの保存書式上邪魔な文字の置換とかいろいろやるんだと思います。

KODAMAR
質問者

お礼

回答ありがとうございます。 >$buf = 'a=b=c=d'; のとき >split(/=/,$buf,2) すれば返る配列は >('a' , 'b=c=d') です。 やっぱりそうなんですね!! 例えば$bufferが3つの構成からなっていて、その2つ目のところに=や&が入ることがある場合、 3と指定してしまうと、2つ目のところの途中で終ってしまうんですよね?

KODAMAR
質問者

補足

すいません、間違ったのを書いたのを送信してしまいました。 $buffer = A=4&B=4=5=6&C=1 だった場合、3を指定したら A=4,B=4,5=6C=1 となってしまうんですよね? A=4,B=4=5=6,C=1 としたいのですが。。。

回答No.1

他のログの方拝見しましたが、 やはり状況が今ひとつわかりません。 >ただ普通にsplitでやってしまうと意図しない&で切れてしまいます。 splitする対象のデータに&があれば当然そこで分割されます。 ただし、普通はsplitされる時には%26になっているはずです。 (ですので、そこで分割されないことになります) もし分割したいのであれば、 splitする前に%26を&に戻しておく必要があります。 >=や&を文章中に使うと、そこで意図しなくてもわかれてしまいますよね? とのレスが前のログにありましたが、 なにかしら勘違いがあると思います。 一度getでデータを渡すなりして確認してみるべきでしょう。 また、 split第三引数の話も他の方のコメントにありました。 これも調べてみることをおすすめします。 #私の方で勘違いありましたらすみません。

KODAMAR
質問者

お礼

回答ありがとうございます。 今一度説明させていただきます。 フォームcgiで入力されたデータをPOSTで別cgi(2.cgi)で取得、ログファイルへ書き込みします。 ●2.cgiの例 read(STDIN,$buffer,$ENV{'content_length'}); $buffer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; ($TITLE,$DATE,$NAKAMI,$WORD,$TIME,$SEARCHKEY)=split(/&/,$buffer,6);    ←ここに「6」を足してみました。    : ($TITLETITLE,$TITLE)=split(/=/,$TITLE); ($DATETITLE,$DATE)=split(/=/,$DATE); $NAKAMI =~ /^(.*?)=(.*)$/;$NAKAMITITLE = $1;$NAKAMI = $2;    : $NAKAMI =~ s/=/%3D/g; $NAKAMI =~ s/&/%26/g;    : open(FH,">>log.log"); @filew = "$TITLETITLE=$TITLE&$DATETITLE=$DATE&……\n"; print FH @filew; close(FH); となってます。 この時点でログファイルをみても「&」のみ(というか&以降)が書き込みされていません。 この時点で&が%26と入力されるようにしたいのですが。 あまり詳しくないながら書いたコードですので、面倒臭いことやってるなーという点も多々あると思いますが、 私にはこのように1つ1つ追っていかないとわからなくなってしまうので…。