Perl正規表現のパターンマッチングで文字数制限の限界はあるのか?

このQ&Aのポイント
  • パターンマッチングにおけるPerl正規表現の文字数制限について調査しました。
  • 長いテキストを対象にした場合、32,768バイトを超えると正しくマッチしない現象が発生します。
  • この制限に関する公式のドキュメントは見つかりませんでしたが、バグとして報告されている可能性があります。
回答を見る
  • ベストアンサー

パターンマッチングの限界?(最大文字数)

perl正規表現のパターンマッチングでは,対象文字列が長すぎると正しくマッチしないというような,perlの仕様あるいはバグが存在するのでしょうか? ■状況 CGIフォームから入力された文字列に機種依存文字(EUC未定義文字)が含まれていないかチェックするため,以下のようなスクリプトを書きました。テストでは,ほとんどの場合は正常に動作しましたが,定義文字=パターンマッチするはずの文字に,未定義文字が含まれていると誤判断されてしまうケースがありました。いろいろ試してみたところ,どうも文字数32,768バイトを超えた場合に限られるようだ,というところまで判りました。 ドキュメントなどを見ても,そのような仕様については見つからず,どなたかご存知ないでしょうか。 あるいはスクリプトに不備があればご指摘いただけたらと思います。 よろしくお願いいたします。 if (&is_undef($input_text)) { print "未定義文字が含まれています。"; } … sub is_undef { my ($text, $character_strict); $text = $_[0]; # EUC-JP文字(定義文字) $character_strict = '(?:[\x20-\x7E]|' # ASCII  . '[\xA1\xB0-\xCE\xD0-\xF3][\xA1-\xFE]|' # 1,16-46,48-83区  . '\xA2[\xA1-\xAE\xBA-\xC1\xCA-\xD0\xDC-\xEA\xF2-\xF9\xFE]|' # 2区  . '\xA3[\xB0-\xB9\xC1-\xDA\xE1-\xFA]|' # 3区  . '\xA4[\xA1-\xF3]|' # 4区  . '\xA5[\xA1-\xF6]|' # 5区  . '\xA6[\xA1-\xB8\xC1-\xD8]|' # 6区  . '\xA7[\xA1-\xC1\xD1-\xF1]|' # 7区  . '\xA8[\xA1-\xC0]|' # 8区  . '\xCF[\xA1-\xD3]|' # 47区  . '\xF4[\xA1-\xA6])'; # 84区 $text =~ s/\r//g; $text =~ s/\n//g; $text =~ s/\t//g; if ($text =~ /^$character_strict*$/) {  return; } else {  return 1; } }

  • Perl
  • 回答数3
  • ありがとう数6

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

  • ベストアンサー
noname#205944
noname#205944
回答No.3

なるほど、 $input_text = 'A' x 32769 を食わしたら Complex regular subexpression recursion limit (32766) exceeded と出ますね やはり、32766バイトが一度にできる限界なのではないでしょうか となると、分けるしかなさそうですね Perlのバージョンは 5.008007 Linux(Redhat7)でも、結果は同じでしたよ どうやら、前回は適当に大きいファイルを丸ごと食わしていたのですが 少し足りなかったようです

taseki
質問者

お礼

ご回答ありがとうございます。 環境に依存するわけではないのですね。 きちんとした(?)警告メッセージが出るかSegmentation faultが起きるかは、バージョンの違いなのかもしれませんね。 しかしこのような要件(何かの原稿を処理するだとか)は少なくない気がするのですが、いろいろドキュメントを探しても見あたらないし、知られていないようなのが気になるところ。 とにかく今回の問題は解決しました。ありがとうございました。

その他の回答 (2)

noname#205944
noname#205944
回答No.2

あまり詳しくはないのですが ASCIIは '(?:[\x00-\x7F]|' # ASCII それと半角カタカナもありです '\x8E[\xA1-\xDF]|' # 半角カタカナ CGIではなく、コマンドで実行したときにも起こりますか? 私も、やってみましたが 特に何事もなくマッチングしていますよ しかし、ちょうど32,768バイトというところが気になりますね

参考URL:
http://www.din.or.jp/~ohzaki/perl.htm
taseki
質問者

お礼

ご回答ありがとうございます。 まずEUCの定義文字部分についてのご指摘ですが、説明不足ですみません。「機種依存文字」と書いてしまいましたが、単純に「入力して欲しくない文字」ということで、ASCIIの一部と半角カタカナも除外したかったのです。 で、本題ですが、コマンドラインから起動しても結果は同じでしたが、Segmentation faultが起きていることが判りました…。ということはperlのバグ? edamsさんは問題なかったとのことですが、ようするに上記スクリプトのif文の前に $input_text = 'A' x 32769; とか書いて実行してもprintメッセージが出ない、ということですよね? 考えられるのは環境の違いですが、もしよろしければperlのバージョンを教えていただけないでしょうか。 ちなみに当方でテストした環境は 5.006 5.00503 5.008004 です( $] の値)。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

全く、自信なしですが submit のGETによる制限ということはないでしょうか? あとは、スタックに積む文字列の長さに限界があるのかも、 関数にリファレンス渡しでやってみるとか

taseki
質問者

お礼

上記、「お礼」とすべきところ間違えてしまいました。失礼しました。

taseki
質問者

補足

ご回答ありがとうございます。 ただ、ご指摘の、そもそも長い文字列を渡せていない?という疑問は私も感じたので、受け取った文字列のバイト数を表示するようにして確認したので、どうもこれはなさそうです。 今いろいろな環境(perlのバージョン)による違いがあるのか試していますが、今のところ同じ現象です。 とりあえず上記のif文の個所を以下のようにして対処していますが、どうも釈然としません…。 1 while ($text =~ s/^$character_strict+//); if ($text eq '') {  return; } else {  return 1; }

関連するQ&A

  • Apacheの400 Bad Request

    macOS 12.6.4にApache(2.4.57)をインストールしています。IPアドレス直打ち対策と、.htaccessによるIPアドレス制限を行った結果、ほとんどの望まないアクセスに対して403を返せるようになりました。 しかし、唯一残っているのが、表題の「400 Bad Request」です。ほぼ特定のIPアドレスからのアクセスなのですが、IPアドレス制限に引っかかってくれません。しかも量が多いのです。(今日の17時から23時までで143件中95件) このアクセスを拒否する方法はありますでしょうか? ログは以下のような感じで意味不明です。(IPアドレスは伏せています) xx.xx.xx.xx - - [13/May/2023:22:47:06 +0900] "\xbb\x04\x01,\x04\x14\x88A\xfbsS\x17S\x17\xca\xe6\t\xf80J\"\xb5\xbf`\xcd<\xab\x9c\xcdY\b\x1fp\xd8\x88\x04\x93&\x1f\x81\xf0_\xf4Z\xc7\xa6\x07Y\xafvn\x8c\xf5l-\x86\x86\x97S\xe3\x10\xd5\xa2\x01\xd7.\xef\x14u\x96\x9b(V\\\xa9z\xe4\x9e=M\xfe\xa6\xcf)7\\A;Fe\xee\x1a\xacIU<\\ \xa6\x1f6\x03|\x11\xe6\xd9U\xaa]\xd3\xfc\x05\x15\xf9\x0e" 400 226 "-" "-"

  • perlで記号除去を行いたいのですがうまく行かない

    perlで記号除去を行いたいのですがうまく行かず困っています。 文字列はEUCです。そこから$patternのような記号を削除したいのですが・・・。 http://www.din.or.jp/~ohzaki/perl.htm#Character 正しくパターンマッチさせる を参考に $ascii = '[\x00-\x7F]'; $twoBytes = '[\x8E\xA1-\xFE][\xA1-\xFE]'; $threeBytes = '\x8F[\xA1-\xFE][\xA1-\xFE]'; $pattern=q([\!!\##\%%\--―ーー・・\//\;;\??\\¥__`‘\{{\}}\++\((\))\[[\] ]\**@@\$$&&\::\>>\<<\~ ̄\^^\"”\'’  \,,\..\==\||\、、\。。]); if ($data =~ s/((?:$ascii|$twoBytes|$threeBytes)*?)(?:$pattern)/$1/mg) { print "マッチした $& \n"; } print $data; として$dataに下の2つを与えてみました。 サンプル1 【あいうえお】 サンプル2 【aaa】 ところが・・・ サンプル1 (出力なし) サンプル2 旻aaa桿 何が悪いのかわかりません・・・ ためしにパターンに【】を追加したところサンプル2はうまく行きましたが サンプル1に変化がありません。(あいうえお も消えてしまう) 何か思い当たる点がありましたら教えてください。よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • ローマ数字の変換をしたいのですが

    言語:perl5.00404 機種依存文字である、ローマ数字を変換したいのですが、 例:ローマ数字の1~10を、I,II,III,IV,V,・・・と変換したい。  試みた方法としては、 &jcode::tr(\$str, "\xAD\xB5", "I"); &jcode::tr(\$str, "\xAD\xB6", "II"); &jcode::tr(\$str, "\xAD\xB7", "III"); &jcode::tr(\$str, "\xAD\xB8", "IV"); &jcode::tr(\$str, "\xAD\xB9", "V"); jcodeを使用して変換。 この方法だと、ローマ数字の1~3は、全て"I"としか 変換してくれず困っています。 (1文字目しか変換されないようなのです。) これではいけないと考え、正規表現で以下のように試みたのですが、 $eucpre = qr{(?<!\x8F)}; $eucpost = qr{ (?= (?:[\xA1-\xFE][\xA1-\xFE])* # JIS X 0208 が 0文字以上続いて (?:[\x00-\x7F\x8E\x8F]|\z) # ASCII, SS2, SS3 または終端 ) }x; $str =~ s/$eucpre(?:\xAD\xB5)$eucpost/$1I/g; $str =~ s/$eucpre\Q\xAD\xB5\E$eucpost/$1I/g; $str =~ s/$eucpre(?:\xAD\xB6)$eucpost/$1II/g; $str =~ s/$eucpre\Q\xAD\xB6\E$eucpost/$1II/g; $str =~ s/$eucpre(?:\xAD\xB7)$eucpost/$1III/g; $str =~ s/$eucpre\Q\xAD\xB7\E$eucpost/$1III/g; $str =~ s/$eucpre(?:\xAD\xB8)$eucpost/$1IV/g; $str =~ s/$eucpre\Q\xAD\xB8\E$eucpost/$1IV/g; $str =~ s/$eucpre(?:\xAD\xB9)$eucpost/$1V/g; $str =~ s/$eucpre\Q\xAD\xB9\E$eucpost/$1V/g; これだとperlのバージョンが対応していない(perl5.005以上だとできる)のでこの策もだめで、困り果てています。どなたかよい方法を教えてください。

    • 締切済み
    • CGI
  • Perl 文字変換

    Perlで全角英数字を半角英数字に変換させたいのですが、 Jcodeを使わずにできる方法を教えてほしいです。 例えば zenkaku→zenkaku のようにです。 $value=~ s/$a\xA3([\xB0-\xB9\xC1-\xDA\xE1-\xFA])$b/pack("C", ord($1) - 0x80)/oeg; こういうのを試してみたのですが、上手く行きませんでした・・・

    • ベストアンサー
    • Perl
  • 黄金分割法

    現在、黄金分割法を用いて、一変数関数の最小化をしようとしています。 黄金分割法はx座標上の4点(xa<xb<xc<xd)を常に保持し、凹型になっている3点の中に次々とxminを追い込んでいく方法です。 文献を参考に黄金分割法のプログラムを作成し、二次関数を用いてテストをしたのですが、最小値を与える座標xminが求まりません。 一番離れている2点(xa,xd)がxminを常に囲っている状態ならば、求まると思うのですが、4点の値をトレースしたところ、4点とも、xminに対して片側に寄ってしまい(例えばxmin<xa<xb<xc<xdというような状態)、求まらないようなのです。 黄金分割法は原理的に上記のように最適化が失敗する可能性があると思うのですが、どうなのでしょうか? 初期状態でxminを囲っていれば、確実に最適化が可能なのでしょうか?

  • cgiで文章を32文字ごとに改行

    cgi初心者です。 入力画面→確認画面→送信 上記のメール送信を作成中なのですが、入力画面で入力した文章を32文字ごとに改行し、もし文章内のURLに改行が入る場合は、URLが終わった後に改行をするようにしたいのですが、出来ません。 コードはEUCになります。 現在は下記ソースになります。 $body = '32文字で改行したい。ただしURL内で改行する時はURL(http://test/htt/test/test/?test=test#test終わりに改行したい。'; $body =~ s/((?:[\xA1-\xFE][\xA0-\xFF]|.){32})/$1\n/go; $body1 =~ s/(htt[\w\.\~\-\/\?\&\+\=\:\/]*)\n([\w\.\~\-\/\?\&\+\=\:\/]*)\n([\w\.\~\-\/\?\&\+\=\:\/]*)/<b>$&<\/b><br>/g; $body1 =~ s/(ht[\w\.\~\-\/\?\&\+\=\:\/]*)\n/$1/g; 文章の文字数を算出し、32文字で割った回数をまわし、32文字ごとに\nをいれてみたりもしてみたのですが、半角が途中に入ると文字化けてしまったりして現在に至ります。 ご教授お願い致します。 cgi初心者な為、コードも添えて頂ければ助かります。

    • ベストアンサー
    • CGI
  • 座標値を求める計算式が知りたい!

    下図のように、点座標、点A(Xa,Ya)、点B(Xb,Yb)、点C(Xc,Yc)が与えられているとき、D点の座標値、Xd, Ydを求める式を教えてください。

  • 日本語のマッチング(正規表現)

    Perl5.8.7で日本語のマッチングを行おうとしてます. 文字コードはEUCで,[ト],[ユ],[ャ],[ュ]や[ョ] の後にある[ウ]を[ー(長音)]に変換しようとする ものです. 例.ヒャクトウバン→ヒャクトーバン 自分の考えた正規表現では成功しませんでした. if($b[$i] =~ /[\xa5e6\xa5c9\xa5e3        \xa5e5\xa5e7]\xa5a6/){ $b[$i] =~ s/\xa5a6/\xa1bd/; } 文字コードを直接書く方法しかないのか, 日本語はマッチングできるのかなどわからないので, よろしくお願いいたします.

    • ベストアンサー
    • Perl
  • 携帯メールで送られてきた絵文字を削除

    携帯メールで送られてきた絵文字を削除したく、 HTML::Entities::ImodePictogram など いろいろ試していますが、うまくいきません。 下のサンプルでは、"絵文字"がハードコーディングだったり、フォームからの入力値ではうまく削除できますが、メールで受けたものでは削除できません。 Jcode を使って文字コード変換してから試してもだめです。 ----------------------------------- $text = "絵文字"; $HTML::Entities::ImodePictogram::ExtPictorgram_re .= '|[\xF3\xF4\xF6\xF7][\x40-\x7E\x80-\xFC]'; $text = remove_pictogram($text); $text =~ s/\x1B\$(.+?)\x0F//g; ----------------------------------- iモードに限らず、ezweb/vodafone live! においても 受け取ったメールの絵文字を自動削除したいのですが、どのようにすればよいでしょうか。

  • Perlのデータ変換

    Perlでデータの変換で方法がわからず、悩んでおります。 $moji_1 = "A5A2A5B9A5D9A5B9A5C8"; ↑ ↓ @moji_2 = (0xA5, 0xA2, 0xA5, 0xB9, 0xA5, 0xD9, 0xA5, 0xB9, 0xA5, 0xC8); それぞれを変換するスマートな(関数や1行程度)でできる方法が知りたいのですが わかりません。 packやunpack?を使えば、できるということでしょうか? perlの取得がなかなかできずに悩んでおります。 Cがポインタが理解できれば初級をクリアしたといわれますが、 Perlの場合は、何をクリアすれば、初心者をクリアしたとなりますか? 皆さんの意見が知りたいです。 初級 中級 上級 達人 仙人 創始者 Perlを作った人 . . .

    • ベストアンサー
    • Perl

専門家に質問してみよう