◀ANSI版開発トップへ
  • 3868 正規表現「(?=regexp)」での置換ができない
    • 3882 RE: 正規表現「(?=regexp)」での置換ができない
      • 3883 RE2: 正規表現「(?=regexp)」での置換ができない
        • 3889 RE3: 正規表現「(?=regexp)」での置換ができない
          • 3896 Re4: 正規表現「(?=regexp)」での置換ができない
            • 3899 Re5: 正規表現「(?=regexp)」での置換ができない
              • 3900 Re6: 正規表現「(?=regexp)」での置換ができない
            • 3903 Re5: 正規表現「(?=regexp)」での置換ができない
              • 3904 Re6: 正規表現「(?=regexp)」での置換ができない
                • 3916 Re7: 正規表現「(?=regexp)」での置換ができない
            • 3908 CBregexpでのEntry Pointの取り扱いについて
              • 3910 RE: CBregexpでのEntry Pointの取り扱いについて
                • 3911 Re2: CBregexpでのEntry Pointの取り扱いについて
                • 3912 Re2: CBregexpでのEntry Pointの取り扱いについて
              • 3913 RE: CBregexpでのEntry Pointの取り扱いについて
                • 3914 RE2: CBregexpでのEntry Pointの取り扱いについて
  • [3868] 正規表現「(?=regexp)」での置換ができない ありさん 2005年03月06日 19:47

    バグ報告です。
    (?=regexp)を使用して置換しようとしましたが
    置換できません。

    例:
    テキストが
    aaabbbb
    aaabbbb
    となっているときに
    置換前に
    aaa(?=b+)
    置換後に
    ccc
    と入力。検索では上記の正規表現でaaaの部分に
    マッチするのですが、置換が行われません。
    なお、(?!regexp)を使用した検索・置換処理はできます。
    • [3882] RE: 正規表現「(?=regexp)」での置換ができない かろと 2005年03月30日 23:10

      >タイトル: RE: 正規表現「(?=regexp)」での置換ができない
      >発言者: ありさん
      >バグ報告です。
      >(?=regexp)を使用して置換しようとしましたが
      >置換できません。

      浦島フォローになりますが・・・・
      まず、置換できない理由を説明します。

      例の「aaa(?=b+)」で検索すると、「aaabbbb」の「aaa」の部分にマッチします。
      サクラでは、このマッチした文字列を切り出して、切り出した文字列に対して
      再度、正規表現ライブラリにて置換処理を行うのですが、
      切り出した文字列は、「aaa」ですから、「aaa(?=b+)」では置換に失敗します。
      #逆に「aaa(?!b+)は、切り出した文字列に対して置換してもマッチするので成功します。

      なんでわざわざ、「aaa」を切り出すんだ?っことなのですが、
      今回のような「先読み」をしなければ問題にならないし、
      恐らく、「置換対象」を「選択文字」「選択始点」「選択終点」と3つ選べるようになっていて、
      正規表現以外の置換と同様に扱うには、これが都合が良かったのかもしれません。
      #推測に過ぎませんが・・・(笑)

      だから、今回の問題に対応するためには、マッチした文字列を切り出さずに、行末までの文字列をそのまま
      正規表現ライブラリに渡すという変更をする必要があります。

      もうすぐお試し版できそうです。
      • [3883] RE2: 正規表現「(?=regexp)」での置換ができない かろと 2005年03月30日 23:54

        >タイトル: RE2: 正規表現「(?=regexp)」での置換ができない
        >発言者: かろと
        >>タイトル: RE: 正規表現「(?=regexp)」での置換ができない
        >>発言者: ありさん
        >>バグ報告です。
        >>(?=regexp)を使用して置換しようとしましたが
        >>置換できません。

        >
        >もうすぐお試し版できそうです。

        こちらをお試しください。
        ちなみに、大改造だったのですが、動作は従来通りと思われます。

        http://homepage1.nifty.com/~karoto/Archive/sakura_lookahead.lzh

        1.5.2.1 ベースです。
        • [3889] RE3: 正規表現「(?=regexp)」での置換ができない かろと 2005年04月03日 02:23


          ・先読みで置換できない不具合
          に加えて、
          ・以下のような0幅マッチで置換対象が分からない不具合

          を対処しました。

          >> (8)「^」⇒「abc」 行頭に abc を挿入
          >>  △[置換(R)] で1個ずつ置換していく場合、処理自体は正常。
          >>   ただし、カーソルも何も表示たれないため、次、どこが置換対象になっているのかが分からないので
          >>   「この行頭は [置換(R)] する、次の行頭とその次の行頭は [下検索(D)] で飛ばしてその次の行頭を [置換(R)]...」


          http://homepage1.nifty.com/~karoto/Archive/sakura_lookahead2.lzh

          1.5.2.1 ベースです。
          • [3896] Re4: 正規表現「(?=regexp)」での置換ができない かろと 2005年04月05日 20:28

            ▼ かろとさん
            > ・先読みで置換できない不具合
            > に加えて、
            > ・以下のような0幅マッチで置換対象が分からない不具合

            一般4289で、
            >>> 興味本位の質問ですが、検索で、後半部分だけを検索する方法は無いのでしょうか。
            >>(?!^)■.*
            >>でどうでしょう?
            >(置換は、なぜか、げんたさんか、もかさんの方法しか使えませんね。)

            がありますが、前回までの変更だけではこれに対応できませんでした。
            この置換をするためには、結局のところ
            置換時にも、1行まるごと正規表現ライブラリに渡してやる必要があります。
            #この対応には正規表現ライブラリの変更も必要

            変更点をまとめますと、
            1.0文字マッチの置換対象がわからない不具合対応
            2.先読み置換が出来ない不具合に対応(一般4289含む)
            3.(^abc|cc)等検索で abc cc の後半ccにマッチしない不具合(開発2858)
            です。

            実行形式:
            http://karoto.hp.infoseek.co.jp/Archive/sakura_lookahead3.lzh

            差分(1.5.2.1):
            http://karoto.hp.infoseek.co.jp/Archive/sabun_lookahead3.lzh

            正規表現ライブラリ(MatchEx, SubstExが増えてます。Match,Substは従来通りのため互換性あり)
            http://karoto.hp.infoseek.co.jp/Archive/BREGEXP.lzh

            • [3899] Re5: 正規表現「(?=regexp)」での置換ができない (全略) 2005年04月06日 11:20

              横ヤリ失礼します

              ▼ かろとさん
              > 1.0文字マッチの置換対象がわからない不具合対応
              これいいですね^^
              ただ普通の検索ダイアログからの検索の時にもマッチ位置が分かってほしいので、ちょっと変更してみてはどうでしょう

              diff --dos -ru backup_sakura_core/CDlgFind.cpp sakura_core/CDlgFind.cpp
              --- backup_sakura_core/CDlgFind.cpp Sat Oct 05 14:17:40 2002
              +++ sakura_core/CDlgFind.cpp Wed Apr 06 10:52:11 2005
              @@ -278,6 +278,8 @@

              /* 前を検索 */
              pcEditView->HandleCommand( F_SEARCH_PREV, TRUE, (LPARAM)m_hWnd, 0, 0, 0 );
              + /* 再描画 2005.04.06 zenryaku 0文字幅マッチでキャレットを表示するため */
              + pcEditView->HandleCommand( F_REDRAW, TRUE, 0, 0, 0, 0 );

              // 02/06/26 ai Start
              // 検索開始位置を登録
              @@ -321,6 +323,8 @@

              /* 次を検索 */
              pcEditView->HandleCommand( F_SEARCH_NEXT, TRUE, (LPARAM)m_hWnd, 0, 0, 0 );
              + /* 再描画 2005.04.06 zenryaku 0文字幅マッチでキャレットを表示するため */
              + pcEditView->HandleCommand( F_REDRAW, TRUE, 0, 0, 0, 0 );

              // 02/06/26 ai Start
              // 検索開始位置を登録
              • [3900] Re6: 正規表現「(?=regexp)」での置換ができない かろと 2005年04月06日 23:03

                >
                >▼ かろとさん
                >> 1.0文字マッチの置換対象がわからない不具合対応
                >これいいですね^^
                >ただ普通の検索ダイアログからの検索の時にもマッチ位置が分かってほしいので、ちょっと変更してみてはどうでしょう

                検索ダイアログは「自動的に閉じる」設定だったので同じ事が起こっている事に気付きませんでした(笑)

                変更に賛成です。
            • [3903] Re5: 正規表現「(?=regexp)」での置換ができない げんた 2005年04月10日 02:18

              >正規表現ライブラリ(MatchEx, SubstExが増えてます。Match,Substは従来通りのため互換性あり)
              >http://karoto.hp.infoseek.co.jp/Archive/BREGEXP.lzh
              これはBREGEXP.dllのlinux版ソースを元に作ったものですか?

              Artistic Licenseの日本語訳
              http://www.opensource.jp/artistic/ja/Artistic-ja.html
              によれば以下のような取り決めがなされています.

              改変を公開して良い場合:
              * 改変部分を標準版の作者が利用して良いことを明記した上で
              * バイナリと共にソースも配布すること

              改変を公開したくない場合:
              * 実行ファイル名を変更
              * 標準版との違いを明記
              * 標準版の入手先を明記

              なので,BREGEXP.DLLという名前のままでソース非公開というのはまずいと思います.
              本体に取り込む以上はこれの配布についても考える必要がありますので突っ込ませて頂きました.

              でもDllHandlerって,失敗したときに別の名前でRetryするように作って無いんですよね.
              名前のリストを渡すか,複数のうちの指定された1つを返すように仕様変更しますかな.
              それかLoadLibraryもvirtualにしてoverloadしてしまうか.
              • [3904] Re6: 正規表現「(?=regexp)」での置換ができない かろと 2005年04月10日 10:24

                >発言者: げんた
                >>正規表現ライブラリ(MatchEx, SubstExが増えてます。Match,Substは従来通りのため互換性あり)
                >>http://karoto.hp.infoseek.co.jp/Archive/BREGEXP.lzh
                >これはBREGEXP.dllのlinux版ソースを元に作ったものですか?
                >なので,BREGEXP.DLLという名前のままでソース非公開というのはまずいと思います.
                >本体に取り込む以上はこれの配布についても考える必要がありますので突っ込ませて頂きました.

                つっこみありがとうございます。どっちかというと公開する方が楽かなと思ってました。
                別にたいそうな変更しているわけでもないですし。
                公開しちゃって、誰でもいじれる方がサクラっぽいですし。
                リポジトリはげんたさん管理って方が統一感あっていいですのでもらっていただけるとうれしい。(笑)

                http://groups.yahoo.co.jp/group/sakura-editor/files/Developer/Source/BRegExp_cvsrep.lzh


                >でもDllHandlerって,失敗したときに別の名前でRetryするように作って無いんですよね.
                >名前のリストを渡すか,複数のうちの指定された1つを返すように仕様変更しますかな.
                >それかLoadLibraryもvirtualにしてoverloadしてしまうか.

                そうなんですよね。別の実行ファイル名にする(K2はこれを選んでる)手も考えたのですが、
                これをするとおっしゃるように複数のDLLを指定して・・・みたいなことをしたくなり、
                ハードルが高くて、手をこまねいてました。
                • [3916] Re7: 正規表現「(?=regexp)」での置換ができない げんた 2005年04月17日 16:56

                  とりあえずBREGEXP改をsourceforgeのダウンロードに登録しました.
                  公開したソースには元のバージョンからの変更点とコードの取り扱いについて記述を追加しました.
            • [3908] CBregexpでのEntry Pointの取り扱いについて げんた 2005年04月11日 01:11

              staticな変数にDLLから取得したEntry Pointを格納して,それがNULLでないときだけ初期化するようになっていますが
              1. デストラクタでFreeLibraryが呼ばれているので,オブジェクトを破棄するとそれ以降の動作が保証されないのでは?
              検索・置換ではCEditViewのオブジェクトを使い回しているので問題ないと思いますが,CBregexpから派生したCRegexKeywordは動的にオブジェクトを生成・破棄されるので,正規表現キーワードを使うとやばいことになりそうです.

              2. コンストラクタでInitを呼んでいますが,そこをたどっていくと仮想関数が使われています.
              コンストラクタでは仮想関数が動かないというお約束になっているのでDLL名も取得できないような気がするんですが,なんで動くんだろう??

              1について,動作が冗長な理由はクラスコメントに書いてあるとおり効率より安全を優先したためです.毎回ロードするのが無駄と感じるのであれば,CBregexpとは別にDLLの管理だけを行うCBregexpDllとかの別のクラスをシングルトンとして作り,CBregexpのコンストラクタでオブジェクトを取得するような形にする必要があるかと思います.

              class CBregexpDll : public CDllHandler {
              public:
              static CBregexpDll* GetInstance();
              ...
              };

              CBregexp::CBregexp() :
              m_dllptr( CBregexpDll::GetInstance() )
              {}

              でもDLL呼び出しのオーバーヘッドが(ポインタ参照1回分)大きくなって,あんまり効果なさそう.
              ::LoadLibraryの2回目以降がWindows内部でカウントしているだけなら手間をかけた割に効果が薄いように思いますが...

              ---
              あとクラスで使う定数は#defineではなくてenumを使ってください.そのわけはスコープがクラス内に閉じこめられるからです.ただ今回の場合は定数を使うのがCBregexpの内部処理だけのようなので,クラスとは関係なくcppファイルの方で定義した方がいいかも.
              • [3910] RE: CBregexpでのEntry Pointの取り扱いについて みく 2005年04月11日 19:21


                (全略)さん作のjregexって、どうなったんだろう。
                とか、囁いてみたりする。
                • [3911] Re2: CBregexpでのEntry Pointの取り扱いについて (全略) 2005年04月11日 19:58

                  ▼ みくさん
                  > (全略)さん作のjregexって、どうなったんだろう。
                  > とか、囁いてみたりする。
                  まいど^^;
                  一応↓でこっそり公開はしています
                  http://qwerty.s2.xrea.com/storage/sakura/comment.html

                  複数行検索とかが中途半端にしかできないのでそれがちゃんとできるようになったら
                  改めて持ってこようかと考えて早1年、、、なーんもやってません^^;
                  普通の正規表現による単一行の検索ではあまり問題もなさそうですので、よかったら遊んでみてくださいな


                  オフトピだけだとアレなのでバグ報告
                  かろとさんの0文字マッチのパッチですが
                  矩形選択で横に一文字も選択せずに複数行選択し文字を入力するとキャレット(?)が残るみたいです
                • [3912] Re2: CBregexpでのEntry Pointの取り扱いについて げんた 2005年04月11日 22:45

                  前回試したときにはNFAをそのまま実装したようなコードで,Perlの正規表現に比べるとパフォーマンスの面で劣るのではないかと考えて見送ったままになっておりました.単純NFAだと2^n回探索するようなパターンでもPerlは速度が劣化しないですし,ワイルドカードが使われていないときは別のアルゴリズムを使うとか.(Perlの正規表現エンジンと比較すること自体酷ですが...)

                  ---
                  ところで,普通に正規表現検索を実装するとある位置から比較して受理されなかったら1文字進んでとなるわけですが,マッチしないとわかった範囲を一気に読み飛ばすアルゴリズムって無いんでしょうかね,BM法みたいに.例えば.*AAだったらAAというパターンが出ない限りは絶対マッチしないので,固定部分を探してから逆に戻るとか.(後方参照があると使えないか...)
              • [3913] RE: CBregexpでのEntry Pointの取り扱いについて かろと 2005年04月12日 00:35

                >タイトル: RE: CBregexpでのEntry Pointの取り扱いについて
                >発言者: げんた

                チェックありがとうございます。

                >staticな変数にDLLから取得したEntry Pointを格納して,それがNULLでないときだけ初期化するようになっていますが
                >1. デストラクタでFreeLibraryが呼ばれているので,オブジェクトを破棄するとそれ以降の動作が保証されないのでは?
                >検索・置換ではCEditViewのオブジェクトを使い回しているので問題ないと思いますが,CBregexpから派生したCRegexKeywordは動的にオブジェクトを生成・破棄されるので,正規表現キーワードを使うとやばいことになりそうです.

                うむ、やばいことになりそうです。
                なんで動いているのか?と思ったら、結局 CRegexKeywordコンストラクタやら InitRegexp() やらで、
                Init()呼ばれてて、LoadLibrary()してるんですね。(笑)
                CBregexpのコンストラクタで Init()するしない・・・ってのは意味ないのに気が付いてませんでした。

                最初に思ったのは、Entry Pointがインスタンス毎にある必要ないよなぁと思って staticにしましたが、
                m_hInstanceも同じようにしないと片手落ちですね。
                とりあえず、staticにするのは、再検討ということで、元に戻します。


                >2. コンストラクタでInitを呼んでいますが,そこをたどっていくと仮想関数が使われています.
                >コンストラクタでは仮想関数が動かないというお約束になっているのでDLL名も取得できないような気がするんですが,なんで動くんだろう??

                そんなお約束が!なんで動くんでしょうね・・デバッグモードで追いかけても仮想関数呼ばれてますね。。


                >1について,動作が冗長な理由はクラスコメントに書いてあるとおり効率より安全を優先したためです.毎回ロードするのが無駄と感じるのであれば,CBregexpとは別にDLLの管理だけを行うCBregexpDllとかの別のクラスをシングルトンとして作り,CBregexpのコンストラクタでオブジェクトを取得するような形にする必要があるかと思います.

                ふむふむ。今回はパスして、元に戻すことにします。


                >あとクラスで使う定数は#defineではなくてenumを使ってください.そのわけはスコープがクラス内に閉じこめられるからです.ただ今回の場合は定数を使うのがCBregexpの内部処理だけのようなので,クラスとは関係なくcppファイルの方で定義した方がいいかも.

                enumだとスコープがクラス内になるのは知っていたので、もちろんそうしたかったのですが、
                enumにすると、 m_ePatType & PAT_BOTTOM というのが出来ないと思ったので、define使ってしまいました。
                でも、m_ePatTypeを enum型にしなければ良かったんですね・・・まずは、enumに修正します。
                • [3914] RE2: CBregexpでのEntry Pointの取り扱いについて かろと 2005年04月12日 00:49


                  修正版は、

                  http://karoto.hp.infoseek.co.jp/Archive/sabun_lookahead4.lzh

                  です。