「C++」はPHPの正規表現ではアウト?
AmazonのWEB Serviceを使って、ソフトウェアの販売ページをPHPとPostgresで作成しています。そこで、思わぬエラーが発生していることに今日になって気が付いた。C++に関する製品を扱ったジャンルでWarning: eregi(): REG_BADRPT:・epetition-operator operand invalid in (PHPのパス) line 100のようなエラーになっているではないですか?エラーが発生している箇所はすぐに特定できました。先日、ジャンルを表示するアルゴリズムを修正したことが原因のようでした。eregi関数という正規表現を扱う関数を用いていたのですが、これが原因だと分かりました。PHPの該当部分の問題点をハイライトするために、簡単な例題を書いてみますと、<?php $text_a = "プログラミング"; $text_b = "プログラミング→C・C++・C#"; header("Content-type: text/html; charset=EUC-JP"); if(eregi($text_a,$text_b,$regs)){ print "「" . $text_a . "」は「" . $text_b . "」に含まれます。<br>"; } if(eregi($text_b,$text_a,$regs)){ print "「" . $text_b . "」は「" . $text_a . "」に含まれます。<br>"; }?>のようなプログラムがあった場合、このプログラムを実行した場合、どのような結果が表示されるでしょうか?もちろん、「プログラミング」は「プログラミング→C・C++・C#」に含まれます。というのも表示されますが、そのほかに上述のwarningが表示されます。これは、プログラムの10行目: if(eregi($text_b,$text_a,$regs)){に変数を代入してみると、原因がよく分かります。if(eregi("プログラミング→C・C++・C#","プログラミング",$regs)){となります。ところが、eregi関数のマニュアル:http://jp.php.net/manual/ja/function.eregi.phpにありますように、第一引数は「string pattern」(文字列の正規表現)であって、「string」(文字列)ではありません。ですから、第一引数に「+」があれば、それはメタ文字と解釈されてしまいます。ですから、それ自体を検索させるためには、エスケープする必要があります。if(eregi("プログラミング→C・C\+\+・C#","プログラミング",$regs)){のようにすればOKです。ところが、先ほどの例題では、「+」は変数$text_bの中に含まれていて、変数の中身は事前には分からないので、エスケープしようがありません。そこで、苦肉の策ですが(もっと良い方法もあると思いますが)、事前に、$text_b = eregi_replace("\+","あいうえおかきくけこ","$text_b");として、「+」を絶対に出現しない「あいうえおかきくけこ」という文字列に変換した上で、それを後で再変換する方法を取りました。<?php $text_a = "プログラミング"; $text_b = "プログラミング→C・C++・C#"; $text_b = eregi_replace("\+","あいうえおかきくけこ",$text_b); header("Content-type: text/html; charset=EUC-JP"); if(eregi($text_a,$text_b,$regs)){ $text_c = eregi_replace("あいうえおかきくけこ","+",$text_b); print "「" . $text_a . "」は「" . $text_c . "」に含まれます。<br>"; } if(eregi($text_b,$text_a,$regs)){ $text_c = eregi_replace("あいうえおかきくけこ","+",$text_b); print "「" . $text_c . "」は「" . $text_a . "」に含まれます。<br>"; }?>としました。これで、Warningは表示されず、「プログラミング」は「プログラミング→C・C++・C#」に含まれます。だけがブラウザに表示されるようになりました。決して、スマートな解決策でなく、以前会社勤めをしていて、これとよく似た処理を提案して、即刻、先輩社員に却下されたのを思い出しましたが、今回は、eregi関数の第一引数にくるものが何百とあるといっても、最初から候補(Amazonのジャンル名)は決まっていて、問題を起こすのが、「C++」の「+」だけであることが分かりましたし、フリーのプログラマーとして気楽にやっているため、これで良しとしました。