正規表現での検出箇所調査について

このQ&Aのポイント
  • C言語版の鬼車ライブラリを利用して、正規表現を使用した検索プログラムを作成しています。しかし、特定のパターンを指定して検出箇所を調べる際に問題が発生しています。
  • onig_search()を使用して特定のパターンに一致する全ての検出箇所を調べたいのですが、最初の1件しか検出されません。
  • 問題が解決せず困っており、どなたか解決策をご存知の方がいらっしゃいましたら、お知恵を貸していただけないでしょうか。
回答を見る
  • ベストアンサー

正規表現について

C言語版の鬼車ライブラリを利用して、ある検索プログラムを作成したいのですが、 1点質問です。 以下のような例文があるおします。 (例) -- 最初の試験、二番目の試験、三番目の試験、最後の試験 -- onig_search()を使用して上記から”試験”のすべての検出箇所を調べたいのですが、 パターンに”試験”を指定してonig_search()をコールしても最初の1件目のみしか 検出しません。 特殊なオプションが必要なのでしょうか? それとも、パターン(正規表現)の書き方が誤っているのでしょうか? 問題が解決せず非常に困っています。 どなたか、解決策をお持ちの方は知恵を貸してください。

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

  • ベストアンサー
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.4

#1/3です。少々訂正。 > startを前回のヒット位置(onig_searchの戻り値)+strへずらしながら startを前回のヒット位置(onig_searchの戻り値) + str 「+ strlen(pattern)」へずらしながら です。でないと無限ループしてしまいますね。

ryouhei_chpo
質問者

お礼

D-Matsu さん 回答ありがとうございます。 > 改めて仕様を読み直してみたら、戻り値が最初のヒット位置というだけで、それとは別に引数の構造体regionにヒット数と開始・終了アドレスが入るんですね。 > 読み違えてました。失礼。 確認ありがとうございます。 > さて、それを踏まえて例示されたコードですが、間違いはなさそうに見えます。 > こちらでも以下の環境下で試してみたのですが、 > > ・OpenSuSE 11.4 x64 > ・gcc 4.5.1 > > 配布元の最小限使用例に対してonig_newのencをUTF8に変えてpatternとstrを質問と同じ状態にしてみただけのコードで再現しますね……。 > ASCIIに直して追試したらUTF-8と同じ結果が出たので、なんとなくですがUTF-8の処理が甘いような印象があります。 > > 「とりあえず回避」というやり方ですが、startを前回のヒット位置(onig_searchの戻り値)+strへずらしながらヒットしなくなるまで一つずつ拾っていく手かと思います。 すいません。再現確認までして頂いて感謝します。 そうですよね。。。 私もこの方法しかないと考えていました。 入力情報(検索対象とパターン)はファイルから読み込む設定値なので、プログラムを変えずに対応できれば と思っていたのですが。。。了解です。 当初、鬼車ライブラリの使用方法の誤りかと思っていのたですが、 そうでもなさそうですね。 深夜に対応ありがとうございました。

その他の回答 (3)

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.3

#1です。 改めて仕様を読み直してみたら、戻り値が最初のヒット位置というだけで、それとは別に引数の構造体regionにヒット数と開始・終了アドレスが入るんですね。 読み違えてました。失礼。 さて、それを踏まえて例示されたコードですが、間違いはなさそうに見えます。 こちらでも以下の環境下で試してみたのですが、 ・OpenSuSE 11.4 x64 ・gcc 4.5.1 配布元の最小限使用例に対してonig_newのencをUTF8に変えてpatternとstrを質問と同じ状態にしてみただけのコードで再現しますね……。 ASCIIに直して追試したらUTF-8と同じ結果が出たので、なんとなくですがUTF-8の処理が甘いような印象があります。 「とりあえず回避」というやり方ですが、startを前回のヒット位置(onig_searchの戻り値)+strへずらしながらヒットしなくなるまで一つずつ拾っていく手かと思います。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

#1 で書かれているように onig_search が 「start⇒rangeの間で最初にマッチした部分」を返す というなら, それは「あなたが思っていた動作」に対して適切なコードではないと思われますが.... region の情報を使ってループ?

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.1

まず「どう呼んでいるか」を提示してもらわないことにはどこが誤ってるのかも指摘しようがないんですが…… API仕様を読んだ感じでは「start⇒rangeの間で最初にマッチした部分」を返すようなので、「意図に合うような呼び出し方をしていない」線が濃厚じゃないかという気はするのですが。

ryouhei_chpo
質問者

補足

D-Matsuさん 回答ありがとうございます。 >まず「どう呼んでいるか」を~ ごもっともです。 コメント用に少し簡易的に編集していますが、 概ねこんな感じです。 ※ --ココカラ-- unsigned char *start, *range, *end; // 正規表現用ポインタ regex_t* reg = NULL; // 正規表現オブジェクト OnigErrorInfo eInfo; char *Target = "最初の試験、二番目の試験、三番目の試験、最後の試験"; char *pattern = "試験"; onig_new(&reg, (unsigned char*)pattern, (unsigned char*)pattern + strlen((char*)pattern), ONIG_OPTION_MULTILINE | ONIG_OPTION_IGNORECASE, ONIG_ENCODING_UTF8, ONIG_SYNTAX_DEFAULT, &eInfo); end = (unsigned char*) (Target + strlen((char*)Target)); start = (unsigned char*) pTarget; range = end; region = onig_region_new(); onig_search(reg, Target, end, start, range, region, ONIG_OPTION_NONE); --ココまで-- で、onig_search()の結果として、構造体regionに格納されるのですが、 該当数を示すregion->num_regs は1 になっており、初回該当の情報のみ格納されています。 確認した感じでは意図通りの呼び方に見えたのですが、 期待値と異なります。。。 どうでしょうか?

関連するQ&A

  • .NET正規表現で(?=...)を使えない?

    お世話になります。 以下のページ(.NET Framework 開発者ガイド>グループ化構成体) http://msdn.microsoft.com/ja-jp/library/bs2twtah(VS.80).aspx に、.NET正規表現について以下のようなパターンがあります。  (?= subexpression) ゼロ幅の正の先読みアサーションです。(略)  (?! subexpression) ゼロ幅の負の先読みアサーションです。(略)  (?<= subexpression) ゼロ幅の正の後読みアサーションです。(略)  (?<! subexpression) ゼロ幅の負の後読みアサーションです。(略) これらは、あるパターンが注目している前/後に現れる/現れないかどうかをチェックするけど、それらをキャプチャーしないというものです。 これを使いたいのですが、使えません。以下はVBScriptのプログラムで、WSCript 5.6および5.7で動作させました。(インデントを表現するために全角空白を使っています。実際に動かしてくださる方はタブ文字かなにかに変換願います) Option Explicit Dim objRegExp ' 正規表現オブジェクト Dim objMatches ' 検索結果 Dim objMatch ' 検索結果 Dim strMessage ' 表示メッセージ Set objRegExp = New RegExp objRegExp.Pattern = "(?<=「)[^」]+(?=」)" objRegExp.IgnoreCase = True objRegExp.Global = True Set objMatches = objRegExp.Execute("カッコ前「カッコ中」カッコ後") WScript.Echo objRegExp.Pattern & " は" For Each objMatch In objMatches  strMessage = " " & objMatch.FirstIndex + 1 & _   " 文字目に見つかりました。" & _   "一致した文字列は " & objMatch.Value & " です。"   WScript.Echo strMessage Next Set objMatches = Nothing Set objRegExp = Nothing ところが、  objRegExp.Pattern = "(?<=「)[^」]+(?=」)" のところで「正規表現で構文エラーになりました」となります。 これを、もっと簡単なパターン、  objRegExp.Pattern = "(?:「)[^」]+(?:」)" とすれば動くことは分かっているんですが、今の私の主眼としては「(?<=...)」および「(?=...)」を使いたいんです。 他に、Word 2007 の VBA を試しましたがダメでした。 正規表現自体は合っているようです。 というのは、以下のテストツールで動作できたからです。 http://www.ultrapico.com/Expresso.htm ということで、これらの新しい .NET 正規表現を VBScript や VBA で動かす方法はあるでしょうか。 よろしくお願いいたします。

  • 正規表現の o オプションの意味が分かりません

    正規表現の質問です。 言語はPerlで組んでいます。 いくつかのhtmlファイルを順に開き、以下のようなコードを実行します。 $http{BODY}=~ /(?<=\[ No\.)([0-9]{$digit})(?= \/ $num)/o; ここで $http{BODY} 読み込んだhtmlファイル $digit 変数。整数値。 $num 変数。整数値。 この正規表現で、 ・・・・[ No.2 / 3 ]・・・・ といった感じの文字列から、この場合は「2」をマッチさせようとしました。 ところが最初に読み込んだファイルではうまくマッチしたのですが、2番目のファイルではマッチしません。 o オプションを外すとうまくいきました。o オプションは変数展開を1回行うとのことです。元のファイルはやたらとでかいので、o オプションを付けたら少しは早くなるかなと思いつけていたのですが。。。 ネットで調べると、 while( $s = <FH> ){ # 一度だけ展開する if ( $s =~ /$arg/o; ){ .... } このような用例で、$argは変数というよりも、セットされた文字列として評価されるとあります。でも前述の正規表現の2つの変数、$digitと$numは普通に値を書き換えられていましたけど。。。 それとも o オプションを付けた正規表現では、その正規表現を処理するためのメモリ領域に一度変数の値を取り込むと、二度と読み込むことをしないということでしょうか。だから変数の値が変わっても、正規表現が用いるメモリ領域の値は変化しない。。。 でも $http{BODY}=~ /(?<=\[ No\.)([0-9]{$digit})/o; だったらちゃんと$digitの値が変わったことに対応しているんです。他にもいっぱい o オプションを付けた正規表現を用いていますけど、全部正常に作動しています(バグに気づいていないだけかもしれませんけど)。 前述の正規表現とこれら正常に作動する正規表現の違いは、後者が変数1個であるのに対して、前者は2個であるということです。「変数展開を1回行う」の意味は、変数1個にしか対応しないという意味なのでしょうか。でも前者も最初のファイルだけなら2個の変数に対応しているのです。 どういうことなのでしょう。

    • ベストアンサー
    • Perl
  • ruby 配列の中の正規表現は比較に使える?

    数万行あるテキストファイルの中を数百パターンくらいの正規表現で サーチするRubyスクリプトを作成しようとしていますがうまくできません。 どなたかお知恵を拝借させてください。 以下の流れで作ろうとしています。 「 ファイルを一行GETして、その行が事前に定義した配列内の正規表現に合致していればprintする。 次の行をGETして、最初からた正規表現の配列を比較して、合致していればprintする。 テキストファイルが終わるまで、繰り返し 」 何分初心者なもので…、他のやり方があれば教えていただきたいです… ヨロシクお願いしますm(__)m

    • ベストアンサー
    • Ruby
  • 正規表現の応用

    C言語のソースコードを扱っています。 デバッグのため(関数がどういう順番で呼び出されているかを知るため)、関数の先頭にprint文をつけようと思っています。 例えば、 int hoge(引数の並び) { 関数の中身 } なら int hoge(引数の並び) { printf("hoge"); 関数の中身 } といった具合です。 関数が膨大なので、手作業で一つずつprintfを書くのは現実的ではありません。 関数の最初の1行のパターンマッチは、/int\s\w*(.*)/ でうまくいくのですが、次の行の{まで含んだ正規表現に対応させるやり方がわかりません。 また、printf文を読み込んだソースコードに挿入するにはどうしたらよいのでしょうか。 どなたか分かる方がいらしたらご教授よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • CSVデータを正規表現で抜き出せません・・・。

    お疲れ様です。初投稿になります。 どうぞ宜しくお願い致します。 CVSデータ(囲い文字:"(ダブルコーテーション))を正規表現でマッチングさせ、抜き出そうと考えています。 エスケープ文字を以下のように設定しています。 ・""(ダブルコーテーション * 2) ⇒ "(ダブルコーテーション) ・\"(円記号 + ダブルコーテーション) ⇒ "(ダブルコーテーション) ・\\(円記号 * 2) ⇒ \(円記号) 例えば・・・ "A",""",BB,"",\",CC,\\,DD""","EEEE","", ですと、「"A"」「""",BB,"",\",CC,\\,DD"""」「"EEEE"」「""」と取れる想定になります。 特に2番目の「""",BB,"",\",CC,\\,DD"""」は、 「"""(←escape),BB,""(←escape),\"(←escape),CC,\\(←escape),DD""(←escape)"」 という想定です。 PHP関数ではエスケープ文字の問題により取得しきれず、自力での取得を行っております。 私が考えた正規表現は「"[^"]*((""|\\")[^"]*)*[^\\]",|"",」となりますが、カンマが入り乱れる上記パターンを満たすことができません。 これは、正規表現での解決は不可能でしょうか? 何日も解決できず、困っています・・・。 是非、皆様のお力添えのほど、宜しくお願い致します。 PS. このサイトで動作確認を行っておりました。 参考になれば幸いです。 http://www.rider-n.sakura.ne.jp/regexp/regexp.php

    • ベストアンサー
    • PHP
  • 正規表現でのマッチを複数取得したい

    正規表現にて、文字列のhtmlタグ部のみを配列にして取得したいのですが、初めにマッチする1つしか返り値を取得できません。 ----ソース--------------------- $this->target_str <<<EOS <test1>aaa</test1> <test2>bbb</test2> EOS; preg_match ( "/<.*?>/imsu" , $this->target_str, $RES_ARR ); ------------------------------- 上の例だと、 $RES_ARR[0] => "<test1>" となり、残りのタグは取得できないのです。 google検索にて発見した、'マッチした後も続けて検索する'というオプション'g'をつけてみたのですが、'g'に対してエラーが出てしまいます。 どなたか解決策をお持ちの方いらっしゃいましたらよろしくお願いします!

    • ベストアンサー
    • PHP
  • C#における正規化について教えて下さい

    現在大学でプログラミングをやっている大学4回生です。 使用言語はC#で、ライブラリ関数としてOpenCvSharpを使用しています。 今現在、類似画像検索機能を実装しようとしているのですが、なかなかうまくいきません。 特徴量は今のところカラーヒストグラムのみでやっています。 流れとしては、 入力画像を読み込み64色に減色した後、順にカラーヒストグラムを算出して要素数が64の配列に格納しています。 ちなみにint型で定義しています。 扱っている画像は900*1200ぐらいサイズから、1800*2700など大きいサイズも多く含まれています。 配列の中は単純にその色の画素数になっていますので、かなりの数になります。 また、画像のサイズの違いによってヒストグラムの合計値にも差がでてきてしまいます。 そこで、それぞれのヒストグラムに正規化を行い、0から任意に指定した最大値までの値で出力し、 比較を行えるようにしたいのですが、どのように正規化を行うのがいいのでしょうか。 正規化できた後は、正規化した2つのヒストグラムをHistogram Intersectionを用いて比較し、類似度を求めようと考えています。 Histogram Intersectionを使うためには正規化を行わないと無理があるのではと思ったので(汗)。 これが1番の理由です... C++等でのやり方はいくつか見つけたのですが、私の力ではそれをC#で使用できるように翻訳することもできなさそうなので... 手法の方はできるだけ詳しく教えていただけると幸いです。 よろしくお願いします!

  • f2cについて

    現在Borland C++ 5.5を使ってFORTRANをC言語に変換しようとしてf2cを使って変換しようとしたのですがうまくいきません。  公式のFAQで一応5.0の解決策であるライブラリの再構築を行ったのですが出力ファイルには何も書かれてませんでした。5.5ではライブラリの再構築を行っても駄目なのでしょうか?また何か解決策があればよかったら教えてください。

  • 秀丸での正規表現:複雑な条件を指定する場合 続き

    この質問は、 http://okwave.jp/qa/q8757880.html の続きです。 具体的な事を全然書いてませんでした。すみません。 Verilog-HDLというハードウェア記述言語での話です。 上記であげたパターンは、サブモジュールのインスタンス記述 (プログラムで言うサブルーチン呼び出しのようなもの)です。 サブモジュールのインスタンス記述を強調したいと思っていますが、それ以外にも always @(posedge clk)begin  if(xxx)begin   ...  end  else if(yyy)begin //←ここで誤検出   ...  end end というサブモジュールでない記述で誤マッチしてしまうのです。 話それてしまいますが always @(posedge clk)begin  if(xxx)begin   ...  end  else begin   if(yyy)begin    ...   end  end end とかけばよい、という手もあるのですが、他者のコードも受け入れる関係上、その手も難しいのが実情です。 話が前後してしまいましたがサブモジュールインスタンス記述は、 sub_mod_name instance_name ( .... のようになっており、1語目、2語目ともに任意の文字列となっています。 else ifともに言語上の予約語であり、これはインスタンス記述にはなり得ません。 『これにマッチする正規表現」かつ『else if(』にはマッチしないというのは、そもそも『ひとつの正規表現』では表せないのかと悩んでおります。 長くなりすみません。 なにか抜けている点などありましたらご指摘頂けると助かります。

  • Windows不正規品仕様の表示

    FMV-F553BDB Windows7を使用ています。 10日ほど前から、「このコンピュータは正規品のWindowsを実行していません」の表示が出ます。オンラインで今すぐ解決の指示に従って操作しますと、「お使いのWebブラウザはが必要なスクリプトを実行するように構成されていないため、検証プロセスを続行できません」との表示です。  最初の表示を削除しても、表面上は問題なく使用できるようですが(本当に正常かどうかは判りませんが)、またしばらくすると同じ表示が出てしまいます。  どなたか解決策をご存じの方、お教え願います。 ※OKWaveより補足:「富士通FMV」についての質問です。

専門家に質問してみよう