文字列探索を忌避するアルゴリズム

  1. // エミュレーター のインナープロパティ
    _window = window; _document = document;
    _dselection = document.selection;
    _result = 0; _keepselect= false;
    _places = [];
    function nameplace(sName){
        var n1 = _dselection.GetActivePointX(mePosLogical);
        var n2 = _dselection.GetActivePointY(mePosLogical);
        _places[sName] = [n1, n2];
    }
    function gotoplace(sName){
        if( ! _places[sName] ) throw new Error(1, sName + " そんな名前の場所はない");
        var arr = _places[sName];
        //_set_point_a();
        _dselection.SetActivePoint(mePosLogical, arr[0], arr[1], _keepselect);
        //return _here_is_not_point_a();
        return; // 暫定的に戻り値無し
    }
    function right(){
        var c = ( arguments.length==1 ) ? arguments[0] : 1;
        //_set_point_a();
        _dselection.CharRight( _keepselect, c);
        //return _here_is_not_point_a();
        return 1; // 暫定的に戻り値固定
    }
    function gokakko(){
        _result = 0;
        nameplace("_start"); // 現在の場所に名前をつける
        _dselection.SelectWord();
        var ch = _dselection.Text;
        _dselection.Collapse();
        gotoplace("_start"); // 名前の場所に移動する
        // 行末や、EOF 直前
        if( ch == "" )  return _result;

        // カーソル後ろに開き括弧があると、行末にいるときでも、SelectWord は選択する。
        var kakkos = "(){}[]<>()〔〕[]{}〈〉《》「」『』【】<>";
        var i = kakkos.indexOf(ch);
        if( i < 0 ) return _result;

        var hash = new Array();
        for( var k = 0; k < kakkos.length; k++){
            hash[ kakkos.charAt(k) ] = ((k%2)==0) ? 1 : -1;
        }

        var searchstrings = [ "[()]", "[{}]", "[\\[\\]]", "[<>]",
            "[()]", "[〔〕]", "[[]]", "[{}]", "[〈〉]",
            "[《》]", "[「」]", "[『』]", "[【】]", "[<>]"
        ];
        var sb = searchstrings[ Math.floor(i / 2) ]; // 1/2 == 0.5
        var direction;
        if( (i%2)==0 ){
            direction = meFindNext;
            // meFindNext の性質
            if( right()==0 ) return _result; // ありえない
        }else{
            direction = meFindPrevious;
        }

        var count = hash[ch]; // init
        // Find( ..., meFindNext) は searchdown2, finddown2 と同じく、
        // カーソル位置も検索対象に含む。だから right() が必須
        var r = _dselection.Find(sb, meFindReplaceRegExp + direction);
        while( r ){
            // 必ず選択状態
            ch = _dselection.Text;
            count += hash[ch];
            if( count == 0 ) break;
            if( direction == meFindNext ){
                if( right()==0 ) break;
            }
            // FindRepeat には戻り値がない。検索に失敗すると beep
            r = _dselection.Find(sb, meFindReplaceRegExp + direction);
        }
        nameplace("_end");
        _dselection.Collapse();
        gotoplace("_end");
        if( count == 0 ) _result = 1;
        else gotoplace("_start");
        return _result;
    }

    _window.Redraw=false;
    gokakko();
    //if( _result && _keepselect ) selectplace("_start", "_end");
    _document.HighlightFind= false; _window.Redraw=true;

     |  kinzoku  |  返信
  2. おおお、こんな長いのが投稿できた。w

    [不具合] LineDown または再描画 
    kuro さん投稿 2009年09月27日 14時47分
    >SetActivePoint() は内部的にカーソル位置を移動するだけなのでスクロールバーは
    kuroさんの「対応する括弧に移動」は、表示領域を外れた括弧へは、
    移動できないような気がする。じっさいテストしてみたら、移動できませんでした。
    SetActivePoint() などカーソル移動関係の解決方法が分かると、ありがたいです。

    >ちなみに、スクロール位置がカーソル位置に追従されてしまうのは、StartOfLine, StartOfDocument,
    >EndOfLine, EndOfDocument, Collapse のメソッドのみです。・・・たぶん。
    Find は追従するはずです。上記にうpしたコードは、エミュレーターの中で使う予定
    の「対応する括弧に移動」コマンドを、単独で使えるようにしたものです。
    表示領域を外れた括弧へも移動できました。Find を使っているからだと思います。

    昔の秀丸マクロには 64KB の壁があって、マクロ本体と、文字列変数の容量が増える
    と非常に遅くなり、 64KB に近づくと停止していました。古いメモリーモデルの名残
    なんですけど(今はその壁はない)。だからマクロを書く人たちは、文字列変数を使わ
    ないアルゴリズムを発達させました。基本的には、描画を停止して、カーソルを画面
    上に動かしまくって処理します。私は、「対応する括弧に移動.js」を見た時は、非
    常に驚きました。カーソルから、文末または文頭まで全部を文字列変数に格納して、
    処理していたんで。

    >ここら辺はスクロール位置に関係なくマクロを組めるように考慮しなきゃいけないですね。
    >ちょっと検討してみます。
    お願いします。フリーソフト作者様に、プレッシャーを与えていたらすみません。
    ゆっくりやってください。

     |  kinzoku  |  返信
  3. > [不具合] LineDown または再描画 

    スクロールバーの追従関係は大体うまいこと行きそうです。

    > kuroさんの「対応する括弧に移動」は、表示領域を外れた括弧へは、
    > 移動できないような気がする。じっさいテストしてみたら、移動できませんでした。

    おかしいなぁ、、、うちの環境だと表示領域外でも移動できてるのですが・・・。
    対応する括弧へ移動もこんなことになるのなら最初から標準機能で入れときゃよかったかもですw

    > 私は、「対応する括弧に移動.js」を見た時は、非
    > 常に驚きました。カーソルから、文末または文頭まで全部を文字列変数に格納して、
    > 処理していたんで。

    うは、気づかれました・・・?w
    ちょっと荒技ですけど、動けばいいんじゃね?というやっつけ仕事っぷりでした。

    > お願いします。フリーソフト作者様に、プレッシャーを与えていたらすみません。
    > ゆっくりやってください。

    ありがとうございます。すぐに新バージョンを公開できず申し訳ございません。
    日曜プログラマなので更新頻度は遅いですが、今後ともよろしくお頼み申し上げます。

     |  Kuro  |  返信
  4. >スクロールバーの追従関係は大体うまいこと行きそうです。
    よかった。

    >> kuroさんの「対応する括弧に移動」は、表示領域を外れた括弧へは、
    >> 移動できないような気がする。じっさいテストしてみたら、移動できませんでした。
    >
    >おかしいなぁ、、、うちの環境だと表示領域外でも移動できてるのですが・・・。
    思い当たる節があったのでテストしてみました。
    「指定文字数で折り返し」の設定で、対応するカッコが、折り返し行をまたいでいると、
    違う場所に移動します。「折り返さない」設定だと問題なく移動できます。

    >日曜プログラマなので更新頻度は遅いですが、今後ともよろしくお頼み申し上げます。
    こちらこそ、よろしくお願いします。

     |  kinzoku  |  返信
  5. > 「指定文字数で折り返し」の設定で、対応するカッコが、折り返し行をまたいでいると、
    > 違う場所に移動します。「折り返さない」設定だと問題なく移動できます。

    ああっ・・・!ほんとですね。。。
    折り返し設定の場合、ぜんぜんダメでした・・・。
    しかし、このマクロを再び理解できるほど脳が回ってないので、修正にちょっと時間ください(汗)

     |  Kuro  |  返信