◀ANSI版開発トップへ
  • 3410 正規表現もどりよみ
    • 3412 RE: 正規表現もどりよみ
      • 3415 Re2: 正規表現もどりよみ
        • 3420 Re3: 正規表現もどりよみ
          • 3421 Re4: 正規表現もどりよみ
      • 3417 RE2: 正規表現もどりよみ
    • 3423 正規表現エンジン差し替え(多分)完了
      • 3424 Re:正規表現エンジン差し替え(多分)完了
      • 3426 RE: 正規表現エンジン差し替え(多分)完了
        • 3427 Re2: 正規表現エンジン差し替え(多分)完了
          • 3429 Re3: 正規表現エンジン差し替え(多分)完了
      • 3428 RE: 正規表現エンジン差し替え(多分)完了
    • 3448 JRegexの質問
      • 3449 RE: 続・JRegex
        • 3451 RE2: 続・JRegex
          • 3452 Re3: 続・JRegex
      • 3450 Re:JRegexの質問
  • [3410] 正規表現もどりよみ (全略) 2004年02月14日 00:29

    BREGEXPでもどりよみを実装してみました、、、
    でこれだったら1から作った方が早いやってことで正規表現エンジン書いてみました

    一応動くだけ動くようになったので持ってきました
    暇な人は遊んでみてくださいな
    http://qwerty.s2.xrea.com/data/sakura_jr.lzh

    一応perlの正規表現を模していますが他にも適当に足してみてあります
    まー遅かったりするかもしれませんが ^^;
    • [3412] RE: 正規表現もどりよみ げんた 2004年02月14日 11:54

      >1から作った方が早いやってことで正規表現エンジン書いてみました
      おお,興味津々.

      >暇な人は遊んでみてくださいな
      まず>>2959のperl正規表現エンジンのバグに当たるパターンを試してみました(極悪)が問題なくマッチしてうれし~.

      次に^.*$というのを試すと
      空行→改行がマッチ
      空行でない→改行を除いた文字列にマッチ
      と一貫性がない.

      .$だと空行の改行はマッチしない.

      正規表現マニアの方々が今まで出てきた各種パターンを試してくれるでしょう.

      >まー遅かったりするかもしれませんが ^^;
      速度は試していません.

      バイナリサイズが本体+40KBなので,これなら本体に取り込んでBREGEXP.DLL無しで動けるようにしたいなと思います.
      正規表現が使える前提だとアウトライン解析とかがだいぶ楽になるので.

      http://qwerty.s2.xrea.com/storage/other/listup.html
      にあるJRegexと添付パッチでコンパイルできるのでしょうか.

      しかしライセンスがちょっと気になる.
      onigurumaはBSD,boost/regexも自由に使える物なのでいいのですが,GNU/regexはGPLだから結果としてGPLになってしまう.

      ---
      ところで,検索対象として文字列の代わりに文字列リストを与えるようなものって作れますかね?
      一般的な正規表現エンジンは入力として連続した文字列を与えるようになっているために,検索のことを考えると内部形式を1行=1連続メモリにせざるを得ません.すると,1行に10万文字くらい入れたときに非常に遅くなる.
      • [3415] Re2: 正規表現もどりよみ (全略) 2004年02月14日 15:44

        ▼ げんたさん
        > >暇な人は遊んでみてくださいな
        > まず>>2959のperl正規表現エンジンのバグに当たるパターンを試してみました(極悪)が問題なくマッチしてうれし~.
        まだバグ残ったままのものをテストしていただいて、すいませんー

        > 次に^.*$というのを試すと
        > 空行→改行がマッチ
        > 空行でない→改行を除いた文字列にマッチ
        > と一貫性がない.
        CBregexをごっそり入れ替えて適当に作ったのでどっかで失敗したのかな?

        > .$だと空行の改行はマッチしない.
        改行を文字と認識しないためですね
        JRegexでは . が [^\r\n\0] になってますから

        > http://qwerty.s2.xrea.com/storage/other/listup.html
        > にあるJRegexと添付パッチでコンパイルできるのでしょうか.
        入れるの忘れてました、、、だいたいできます
        cppとしてコンパイルすると何カ所かキャストの警告出ます、が、動いてます

        > しかしライセンスがちょっと気になる.
        > onigurumaはBSD,boost/regexも自由に使える物なのでいいのですが,GNU/regexはGPLだから結果としてGPLになってしまう.
        JRegexはうちがフルスクラッチでかきおこしたものです
        作るときにonigurumaとRuby/regexは見ましたがコピーしたコードは一つもありません
        胸を張ってオリジナルだと言い切れるのでライセンスは自由にできます
        # で、今googleで検索したらJavaの正規表現ライブラリでJRegexってすでにあるんですね、、、関係ありませんので

        > ---
        > ところで,検索対象として文字列の代わりに文字列リストを与えるようなものって作れますかね?
        > 一般的な正規表現エンジンは入力として連続した文字列を与えるようになっているために,検索のことを考えると内部形式を1行=1連続メモリにせざるを得ません.すると,1行に10万文字くらい入れたときに非常に遅くなる.
        できますよ
        検索対象文字列として以下のような関数ポインタ渡せるようになっておりこれを経由で呼び出せばいいです
        tchar (*PATTERN_FUNC)(dword,void*);
        文字 (*PATTERN_FUNC)(検索位置,ユーザ定義);
        ついでにやろうと思ったんですけどエディタ側がバイト配列用意してくれるので甘んじてさぼってしまいました
        これはあんまりテストしてない機能なんであやしいです^^;
        • [3420] Re3: 正規表現もどりよみ かろと 2004年02月15日 21:00

          ご無沙汰してます。
          なんだか興味深いものが出てきましたね。

          ▼ (全略)さん
          > ▼ げんたさん
          > > .$だと空行の改行はマッチしない.
          > 改行を文字と認識しないためですね
          > JRegexでは . が [^\r\n\0] になってますから

          うむむ。sakuraの為に作ってもらったような仕様ですね。
          ということは、これはこれで、良さそうですね。

          私もつまみ食いさせていただきました。

          あれ?0文字マッチしない?
          「^」を検索したり、「a*」検索したりで、0文字マッチしないですね。
          こういう仕様かな?

          ちょいとソース見せてもらいました。

          if(!jreg_exec(m_reg, pat, start, len, (jreg_opt)opt)) { return false; }
          else if(m_reg->pBackRef[0].dwMatchCnt <= 1) {
          // マッチ幅が0文字の時非マッチとする
          return false;
          }

          ここで、わざわざ0文字マッチを非マッチにしてるのかな?
          なぜ?

          • [3421] Re4: 正規表現もどりよみ (全略) 2004年02月15日 22:17

            ▼ かろとさん
            > ▼ (全略)さん
            > > ▼ げんたさん
            > > > .$だと空行の改行はマッチしない.
            > > 改行を文字と認識しないためですね
            > > JRegexでは . が [^\r\n\0] になってますから
            >
            > うむむ。sakuraの為に作ってもらったような仕様ですね。
            > ということは、これはこれで、良さそうですね。
            とりあえず手元にある教典(perl)に従ってます^^


            > ここで、わざわざ0文字マッチを非マッチにしてるのかな?
            > なぜ?
            あら、、、恐らく元の位置にあった
            if(matched==0) return false;
            を勘違いして実装してしまったようですね、全然違いますね、修正しときます

            # あぁ、呼び出し側で0文字幅マッチしないと思って修正したコードがぁ;_;
      • [3417] RE2: 正規表現もどりよみ みく 2004年02月15日 09:49


        >>1から作った方が早いやってことで正規表現エンジン書いてみました
        >おお,興味津々.
        +1

        >正規表現が使える前提だとアウトライン解析とかがだいぶ楽になるので.

        私はマクロに使っているWSHを汎用化してアウトラインで使えないかと考えているところです。
        (一般ユーザにとっては、プラグイン.DLLよりは敷居が低くなるはず)
    • [3423] 正規表現エンジン差し替え(多分)完了 (全略) 2004年02月18日 13:26

      正規表現エンジンの差し替え作業終わりました
      恐らくBREGEXP版と動作は大差ないと思います

      バイナリ+差分: http://qwerty.s2.xrea.com/data/sakura_jr20040218.lzh
      ソース全部: http://qwerty.s2.xrea.com/data/sakura_core20040218.lzh

      取り入れてもらえれば幸いです

      #この版はBREGEXP用のソースを削除してあります、書いてた人すいません
      • [3424] Re:正規表現エンジン差し替え(多分)完了 かろと 2004年02月18日 20:50

        ▼ (全略)さん
        > 正規表現エンジンの差し替え作業終わりました
        > 恐らくBREGEXP版と動作は大差ないと思います

        おお!ご苦労様です。
        サッカー見ながらちょっと使ってみました。

        まだちょっとしか使ってないけど、かなりいい出来だと思います。
        早く本流に組み込まれるといいなぁ。。

        少しオリジナルと異なる動作を見つけたので報告しますね。

        ・「\r\n」→「\r」で、改行文字を置換しようとすると、改行がなくなります。
        ・「abc」→「ABC$&」で、Perlで言う特殊変数 $&(マッチ文字列) が使えない。


        あと、動作とは関係ないですが、

        <クラス CRegexpへの提案>
        正規表現が内蔵されると、このクラスをあちこちで使うでしょうから、見やすくするためにもメンバ関数の引数を減らした方がいいかなと思います。
        つまり、マッチ位置・マッチ幅・置換後文字列・置換後文字列長は、インライン型のメンバ関数で取得する。

        クラス定義で、

        bool Match(const TCHAR *target, int len, int start, int *matchs, int *matchr, int opt);
        bool Replace(const TCHAR *target, const TCHAR *repstr, int len, int start, TCHAR **out, int *outs, int *matchs, int *matchr, int opt);
        を、
        bool Match(const TCHAR *target, int start, int end, int opt = 0); // start, end の順番の方がわかりやすいかな?というので順番変えてます
        bool Replace(const TCHAR *target, int start, int end, const TCHAR *repstr, int opt = 0);
        int GetIndex(void); // マッチ位置 (BREGEXPのstartp
        int GetLastIndex(void); // マッチ文字列の最後 (BREGEXPのendp
        int GetMatchLen(void) // マッチ幅
        TCHAR *GetRepStr(void) // 置換後文字列
        int GetRepStrLen(void) // 置換後文字列長

        という感じ(メンバ関数名は適当)にする。
        を提案します。ご検討ください。

      • [3426] RE: 正規表現エンジン差し替え(多分)完了 げんた 2004年02月19日 02:07

        最初に関係ないことで申し訳ないですが,diffは-uの方が-cより差分が見やすくないですか?

        あと,中をまだ見ていないうちに質問して申し訳ないんですが,大文字小文字の区別は何ともならないのでしょうか.同一視できないならまだ正規表現で逃げられますが,区別できないのはちょっと...

        うまくいくようになったら1.5.0.0として取り込みたいと考えています.
        • [3427] Re2: 正規表現エンジン差し替え(多分)完了 (全略) 2004年02月19日 09:43

          まとめて、返信させてもらいます

          ▼ かろとさん
          > ・「\r\n」→「\r」で、改行文字を置換しようとすると、改行がなくなります。
          改行文字前後の関係がちょっとおかしいですね、見直します

          > ・「abc」→「ABC$&」で、Perlで言う特殊変数 $&(マッチ文字列) が使えない。
          必要かどうか迷ったので、入れてませんでした
          \nの後方参照と\xnnnの文字を表すメタキャラクタが使えます
          # 今気づきました、ドキュメントに書き忘れた;_;

          ▼ げんたさん
          > 最初に関係ないことで申し訳ないですが,diffは-uの方が-cより差分が見やすくないですか?
          diffは他のGUIツール使ってたので気にしてませんでした^^;
          -cにしときます

          > あと,中をまだ見ていないうちに質問して申し訳ないんですが,大文字小文字の区別は何ともならないのでしょうか.同一視できないならまだ正規表現で逃げられますが,区別できないのはちょっと...
          あとでまとめて直そうと思って常に大文字小文字無視の設定で通していましたが
          上のURLの20040218版ではちゃんと直したと思ってたんですが、、、直ってなかったですか、すいません、確認します
          # 正規表現キーワードは常に大文字小文字を区別します、これも //i などに対応するかな、、、
          • [3429] Re3: 正規表現エンジン差し替え(多分)完了 かろと 2004年02月19日 23:12

            ▼ (全略)さん
            > > ・「abc」→「ABC$&」で、Perlで言う特殊変数 $&(マッチ文字列) が使えない。
            > 必要かどうか迷ったので、入れてませんでした

            マッチ列を参照する方法は欲しいなぁ

            > \nの後方参照と\xnnnの文字を表すメタキャラクタが使えます

            \1 \2 で参照できるのは気がつきました($1 が使えなかったので次に試したのは \1)

            あと、
            ・\x82a0 で文字検索しようとすると、\x が 0 にマッチしてしまうみたいです


            > 上のURLの20040218版ではちゃんと直したと思ってたんですが、、、直ってなかったですか、すいません、確認します

            私が見たところ、直っていると思いますよ。

            > # 正規表現キーワードは常に大文字小文字を区別します、これも //i などに対応するかな、、、

            そうですね・・・//k とかユーザには関係ないから要らないかなと思ってましたが、/i があったんですね。
            互換性のことを考えて正規表現キーワードは //でかこんで、i を付けられるようにしておくのも手ですね。

      • [3428] RE: 正規表現エンジン差し替え(多分)完了 みく 2004年02月19日 20:24


        \z で検索するとキャレットが見えないです。
    • [3448] JRegexの質問 げんた 2004年02月29日 18:37

      JRegexのソースと格闘中です.脳内設計図だけでコメント0のこれを作ったとしたらかなり神業ではないかと...
      少なくとも関数の入出力は明確に定義しておかないと,あとで改造しようとするときに間違いなくはまりますね.

      以下行番号は2004-02-18版に入っていたJRegex.cのものです.

      jreg_comp()
      196行目: if(pReg->pBackRef && pReg->pdwClosure)で,片方だけメモリ取得に失敗するとリークしますよね.

      193行目: 正規表現の中に反復が全くない場合にpReg->dwClosureCntが0になるようですが,Borland Cではサイズ0のmallocに対してNULLが返る実装になっているので,malloc(sizeof(dword)*pReg->dwClosureCnt
      );でちょっといやなことになりそう.

      jreg_exec()
      215行目: (!Pattern.PATTERN_FUNC && !pReg->Pattern.PATTERN_FUNC)
      今回か前回のどちらかで設定されていればOKと判定されているのに
      pReg->Pattern = Pattern;
      では常に今回のパターンで上書きされてしまう.

      あと,Unionなので2回目に文字列としてNULLを与えた場合も前回の文字列から探しに行きそうな気がしますが.

      その他異常パターンの対応に,反復文字を先頭に置いた場合の対応が不十分なようです.
      ab|+cdはコンパイルエラーになりますが,ab|?cdは通ってしまう.
      また{}はjreg_parse()で戻り値チェック無しでpNodeにアクセスしているため,先頭に置くとアプリケーションエラーになります.

      まだまだ解析継続中ですが,以下ご教授ください.
      jreg_get_cnt()は何を返す物なのでしょうか?
      戻り値0をエラーとするためになんか下駄を履かせているみたい.
      本当は他の関数と構造体の要素や定義してある定数なんかも全部解説して欲しいところではありますが.

      以下自分なりに解析した結果を置いておきます.
      http://members.at.infoseek.co.jp/sakura_editor/JRegex_analysis.txt
      • [3449] RE: 続・JRegex げんた 2004年03月01日 01:14

        解析続行中.まだ正規表現のコンパイル部分の解読途中です.
        気づいた点をいくつか.

        文字クラス[]において,]や-を文字として認識させるためには[]の先頭に置くというルールが実装されていないようです.(説明書でも触れられていませんでしたね)
        ]とABCのどれか→[]ABC]
        -とABCのどれか→[-ABC]
        どうも,BREGEXP(=perl?)では-は最後に置いてもOKのようです.
        -とABCのどれか→[ABC-]
        ]と-を両方マッチさせるには
        -と]とABCのどれか→[]ABC-]

        :alpha:のような記述で,jreg_ccの呼び出し側は大括弧の中身だけを渡そうとしているのにjreg_ccでは大括弧の存在を前提にしているため[:alpha:] では:,a,l,p,hのいずれかにマッチしてしまいます.期待する動作をさせるためには[[:alpha:]]と[]を二重にしなくてはならない.私はこの記法を使ったことがないのですが,意図的にこうなっているんでしょうか.

        jreg

        613行目: 繰り返し{,}の解析後のif文で
        pNode->Data.Closure.dwLower!=pNode->Data.Closure.dwLower
        うーん,!=の両辺が全く同じなんですが...間違ってません?

        --
        その他,弱点を狙った実験をちょっとやってみました.
        ==の60回程度の繰り返しに対して,マッチしないパターンを色々.

        =*A→一瞬でNot found
        (=)*A→一瞬でNot found
        (=+)*A→フリーズ(=が10文字程度ならすぐにNot Found)
        (=*)*A→アプリケーションエラーも出ないでプロセス消滅.

        closureが一重のケースは=の数kに対してO(k)で,マッチするまで1文字ずつ進めていくからΣO(k){k=1..n}でO(n^2)のオーダーなのに対し,二重の方は1つ目と2つ目の境目の取り方がk-1パターンあるのでO(n^3)になるという理解で正しいのかな.

        最後のパターンはなんでお亡くなりになるんでしょう?スタックオーバーフロー?=の数を10程度に減らしてもダメでした.

        マルチラインで検索を行いたいという話がありますけど,文書の頭からひとかたまりと見なして探索を行うと.+のようなパターンでトンでとんでもなく時間がかかる可能性もありますね.
        • [3451] RE2: 続・JRegex げんた 2004年03月01日 02:40

          間違ってました.
          >二重の方は1つ目と2つ目の境目の取り方
          O(n^3)は(=+)(=+)というパターンでした.このパターンならすぐにマッチが終了します.
          (=+)*というパターンは連続する=の分割方法すべてにマッチするんですね.*があると0文字マッチが入ってパターンが無限になるので(=+)+で考えると,=がn個連続していたら(n-1)ある隙間のそれぞれで分割する・しないのオプションがあるので全部2^(n-1)通りとなり,計算量O(2^n)ですね.
          • [3452] Re3: 続・JRegex げんた 2004年03月01日 08:51

            >>二重の方
            2^nは1カ所からの場合で,見つからなかった場合に先頭をずらしながらマッチ位置を探すことを考慮するとO(n*2^n)ですか.

            極悪なパターンを見ていて思ったのですが,(AB[CDE]FG)+とか()にclosureが付いているケースで後方参照を使ったら何が参照されるべきなのでしょうか.今のソースでは1回目が\1, 2回目が\2とはならないですよね.
      • [3450] Re:JRegexの質問 (全略) 2004年03月01日 01:21

        ▼ げんたさん
        > JRegexのソースと格闘中です.脳内設計図だけでコメント0のこれを作ったとしたらかなり神業ではないかと...
        > 少なくとも関数の入出力は明確に定義しておかないと,あとで改造しようとするときに間違いなくはまりますね.
        関数のコメントくらい入れてから公開しようかとおもったのですが面倒くさくなってやめました(ぉ
        # 脳内設計図以外ありません^^;

        *抜粋して返事します

        > 193行目: 正規表現の中に反復が全くない場合にpReg->dwClosureCntが0になるようですが,Borland Cではサイズ0のmallocに対してNULLが返る実装になっているので,malloc(sizeof(dword)*pReg->dwClosureCnt
        > );でちょっといやなことになりそう.
        これはmallocをラップする関数で対処するのがスジですかね?
        jectlib.cに_db_mallocなんておあつらえ向きの関数があったりします

        > あと,Unionなので2回目に文字列としてNULLを与えた場合も前回の文字列から探しに行きそうな気がしますが.
        あれ?そういう仕様でしたっけunionって、、、確認しておきます

        > その他異常パターンの対応に,反復文字を先頭に置いた場合の対応が不十分なようです.
        > ab|+cdはコンパイルエラーになりますが,ab|?cdは通ってしまう.
        > また{}はjreg_parse()で戻り値チェック無しでpNodeにアクセスしているため,先頭に置くとアプリケーションエラーになります.
        この点については確認修正しておきました、ありがとうございます

        > jreg_get_cnt()は何を返す物なのでしょうか?
        > 戻り値0をエラーとするためになんか下駄を履かせているみたい.
        これの意味は戻り読みを行うときのみにしか役に立ちません
        正規表現戻り読みでは (?<=a*c) なんてのはエラーになりますよね?
        この関数は正規表現がマッチした場合の文字数を返すのです
        a* や b+ 、 c? などといったマッチした場合何文字になるか分からないものについてはエラーが返されます
        ただし a{3} は確実に3文字にしかマッチしないので可となるのですが、、

        > 本当は他の関数と構造体の要素や定義してある定数なんかも全部解説して欲しいところではありますが.
        いまの急に仕事で忙しいのが来てしまったのでそれさえ終われば整備します;_;

        # こんなへんちくりんなソース解析させてしまってすいません