「検索ヒット数表示(選択文字列)」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
(→‎ソースコード: ZIP を追加)
 
(同じ利用者による、間の1版が非表示)
1行目: 1行目:
ks 氏の「[[includeライブラリ]]」の StringEx.js(count 関数)と「[[検索ヒット数表示]]」マクロをもとに作成。
 
 
 
== 単独マクロバージョン ==
 
== 単独マクロバージョン ==
  
* アクティブなタブの文書内から選択範囲の文字列に '''完全一致''' するものをカウントする。
+
* アクティブなタブの文書内から選択範囲の文字列に一致するものをカウントします。
* ヒット件数はステータスバーに表示する。
+
* ヒット件数はステータスバーに表示します。
 
 
選択範囲のある状態でマクロを手動で実行するか、「選択範囲が変更されたとき」のイベントマクロに設定して自動で実行させるのがよろしいかと。
 
 
 
 
 
<span style="color:#c00;">※ このマクロと Mery 標準の検索メソッドとでは、ヒット数のカウントの仕方が異なります。 </span>
 
:Mery の検索ではヒットした文字列の「先頭位置より1文字うしろ」から再検索しますが、このマクロではヒットした文字列の「末尾位置」から再検索します。
 
:''e.g.''「あ<span style="background:#bfdfff;">ああ</span>ああ」5文字だけの文書で「<span style="background:#bfdfff;">ああ</span>」を検索した場合、このマクロでは "2件" とカウントしますが、Mery の検索メソッド(次/前を検索)では "4回" ヒットします。<br> また、「あい<span style="background:#bfdfff;">あいあ</span>」5文字だけの文書で「<span style="background:#bfdfff;">あいあ</span>」を検索した場合は、このマクロでは "1件" とカウントします(Mery の検索メソッドでは "2回" ヒット)。
 
:→ 「何件目」かの表示は、上の例のような範囲選択をしている場合には不正確な値を返します。
 
 
 
 
 
※ このマクロの実行にあたって include ライブラリは不要です。
 
 
 
※ このマクロでは、イベントマクロで利用する場合の処理速度を優先させるために「[[検索ヒット数表示]] (JScript)」 マクロのような正規表現検索には対応させていません。また、文字列のヒット判定では「大文字と小文字を区別する」が適用され、「単語のみを検索する」は適用されません。
 
 
 
※ イベントマクロで利用する場合は「'''遅延時間'''」を適宜調整しないと、大きな文書の編集のさいに動作が "もたつく" ことがあります。
 
 
 
 
 
オプション指定をつけてヒット数を調べたい場合は、「[[ポップアップメニューで検索先にジャンプ|ポップアップメニューで検索先にジャンプ]] 」マクロの '''include''' 版をご利用ください(イベントマクロにはできませんが)。
 
 
 
 
 
※ 高度な(煩雑な)動作設定が可能な [[#機能強化バージョン|機能強化バージョン]] を追加(2019/08/26)
 
  
 +
: 選択範囲のある状態でマクロを手動で実行するか、「選択範囲が変更されたとき」のイベントマクロに設定して自動で実行させることができます。
 +
<br><br>
 +
; 設定項目: '''''countMinimum'''''
 +
:Mery の検索ではつねにヒットした文字列の「先頭位置より1文字うしろ」から再検索しますが、このマクロではヒットした文字列の「末尾位置」から再検索できます。
 +
<br>
 +
:''e.g.''「あ<span style="background:#bfdfff;">ああ</span>ああ」5文字だけの文書で「<span style="background:#bfdfff;">ああ</span>」を検索した場合、このマクロでは "2件" とカウントさせることができますが、Mery の検索メソッド(次/前を検索)では "4回" ヒットします。<br> また、「あい<span style="background:#bfdfff;">あいあ</span>」5文字だけの文書で「<span style="background:#bfdfff;">あいあ</span>」を検索した場合は、このマクロでは "1件" とカウントさせることができます(Mery の検索メソッドでは "2回" ヒット)。
 +
:→ 少なくカウントする設定にした場合、「何件目」かの表示は、上の例のような範囲選択をしている場合には不正確な値を返します。
 +
<br>
 +
; 設定項目: '''''matchCase'''''
 +
: 文字列のヒット判定では「大文字と小文字を区別する」を適用するかどうかを選択できます。
 +
<br><br>
 +
※ イベントマクロで利用する場合の処理速度を優先させるため、正規表現での検索処理が必要な「単語のみを検索する」は適用できません。
 +
<br>
 +
<span style="color:#c00;">※ イベントマクロで利用する場合は「'''遅延時間'''」を適宜調整しないと、大きな文書の編集のさいに動作が "もたつく" ことがあります。</span>
 +
<br><br>
 +
[[#機能強化バージョン|機能強化バージョン]] を追加(2019/08/26 → 更新 2019/12/03)
 +
<br>
  
 
=== ソースコード ===
 
=== ソースコード ===
  
2019/07/20 更新
+
2019/12/03 更新
 
*全体のヒット件数のうしろに「何件目」のヒットかを追加
 
*全体のヒット件数のうしろに「何件目」のヒットかを追加
 +
*ヒット数のカウント方法を設定変数で指定
  
 
<source lang="javascript">
 
<source lang="javascript">
44行目: 39行目:
 
  * 選択範囲のある状態でマクロを手動で実行するか
 
  * 選択範囲のある状態でマクロを手動で実行するか
 
  * イベント「選択範囲が変更されたとき」に設定して自動で実行させる。
 
  * イベント「選択範囲が変更されたとき」に設定して自動で実行させる。
*
 
* ※ ks 氏の『includeライブラリ』より
 
*    >> include/StringEx.js >> String.prototype.count()
 
*  のコードを拝借した。
 
 
  */
 
  */
  
var timerStart = new Date();
+
var start = new Date();
Status = "";
+
 
 +
// ■ 「あああああ」にたいして「ああ」のヒット数 (ture: 2 件、 false: 4 件)
 +
var countMinimum = true; // Mery の検索方式にあわせるなら false に
  
var d = editor.ActiveDocument;
+
// ■ 大文字と小文字を区別するか? (ture: する、 false: しない)
var s = d.selection;
+
var matchCase = false;
var word = s.Text;
 
  
if ( word ) {
+
// ■ ヒット数検索の所要時間を表示するか?
  var len = word.length;
+
var timerEnable = true;
  var dText = d.Text;
 
  
  // 大文字/小文字の区別なしにするなら、次の2行をアンコメントせよ
+
var d = editor.ActiveDocument, s = d.selection;
  // word = word.toLowerCase();
+
var word = matchCase ? word : word.toLowerCase();
  // dText = dText.toLowerCase();
 
  
   var tPos = Math.min( s.GetActivePos(), s.GetAnchorPos() )
+
if ( word ) {
   var pos = 0, count = 0, hit = 0;
+
  Status = "";
 +
  var docu = matchCase ? d.Text : d.Text.toLowerCase();
 +
   var tPos = Math.min( s.GetActivePos(), s.GetAnchorPos() );
 +
   var count = 0, hit = 0, append = "*";
 +
  var next = countMinimum ? word.length : 1;
 +
  var pos = docu.indexOf( word );
 
   while ( pos >= 0 ) {
 
   while ( pos >= 0 ) {
     pos = dText.indexOf( word, pos );
+
     count ++;
     if ( pos >= 0 ) {
+
     if ( pos <= tPos ) {
       count ++;
+
       hit = count;
       if ( pos == tPos ) {
+
       if ( pos == tPos ) { append = ""; }
        hit = count;
 
      }
 
      pos += len;
 
 
     }
 
     }
 +
    pos = docu.indexOf( word, pos + next );
 
   }
 
   }
   var SeparateNum = function( num ) {
+
 
    return num.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," );
+
   Status = ( " ヒット数:" + count + " 件"
 +
            + " ( " + hit + " 件目" + append + " ) "
 +
          ).replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
 +
  if ( timerEnable ) {
 +
    Status += "  [ "
 +
            + ( ( new Date() - start ) / 1000 ).toFixed( 3 )
 +
                                              .replace( /\./, ". " )
 +
            + " 秒 ]";
 
   }
 
   }
  Status = " ヒット数:" + SeparateNum( count ) + " 件"
 
        + " ( " + SeparateNum( hit ) + " 件目 ) ";
 
  var TimerElapsed = function( end, start ) {
 
    var elapsedSec = ( ( end - start ) / 1000 ).toFixed( 3 );
 
    return "  [ " + elapsedSec.replace( /\./, ". " ) + " 秒 ]";
 
  }
 
  // 検索所要時間の表示が不要なら、次の1行をコメントアウトせよ
 
  Status += TimerElapsed( new Date(), timerStart );
 
 
}
 
}
 
</source>
 
</source>
 
+
<br>
  
 
== 組み込み用関数バージョン ==
 
== 組み込み用関数バージョン ==
  
2019/07/20 追加
+
2019/07/20 追加、 2019/12/03 更新
*引数に指定した文字列の出現回数 "'''ヒット数:n 件 ( m 件目 )''' " を返す。
+
*引数に指定した文字列の出現回数 "'''ヒット数:n 件 ( m 件目 )''' " を返します。
 
+
<br>
※「[[バイト数]]」マクロなどへの追加コードとして利用できます。
+
動作仕様・制限事項は [[#単独マクロバージョン|単独マクロバージョン]] に準じます。
 
+
<br>
引数が「選択範囲の文字列」でない場合は、キャレット位置までのヒット数を「m 件目」として返します(ただし、キャレットのすぐ右に指定文字列がある場合は、『m 件目』の値 + 1 で返します)。
 
 
 
※ その他、仕様・注意事項については [[#単独マクロバージョン|単独マクロバージョン]] に準じます。
 
  
 
=== 使用例 ===
 
=== 使用例 ===
 
<source lang="javascript">
 
<source lang="javascript">
// 例. ステータスバーの表示内容に追加
+
// 選択範囲の文字列のヒット数をステータスバーの表示内容に追加
if ( document.selection.Text ) {
+
var word = document.selection.Text;
   Status += "  " + HitStatus( document.selection.Text );
+
if ( word ) {
 +
   Status += "  " + HitStatus( word, true, false );
 
}
 
}
 
</source>
 
</source>
114行目: 104行目:
 
<source lang="javascript">
 
<source lang="javascript">
 
/*  
 
/*  
  * 関数 HitStatus( str )
+
  * 関数 HitStatus( word, matchCase, countMinimum )
 
  * 引数に指定した文字列の出現回数 "ヒット数:n 件 ( m 件目 ) " を返す
 
  * 引数に指定した文字列の出現回数 "ヒット数:n 件 ( m 件目 ) " を返す
  * 引数 str: 選択範囲の文字列などの「文字列」オブジェクト
+
  *  
  * ※「大文字/小文字の区別なし」にしたい場合は、コメントアウトされた toLowerCase の行をアンコメントする
+
* 第一引数 str: 選択範囲の文字列などの「文字列」オブジェクト
 +
  * 第二引数 matchCase: 大文字と小文字を区別するなら true、区別しないなら false
 +
* 第三引数 countMinimum:「あああああ」にたいして「ああ」のヒット数を
 +
*                        2 件とカウントするなら true、4 件とカウントするなら false
 
  */
 
  */
function HitStatus( str ) {
+
function HitStatus( word, matchCase, countMinimum ) {
   if ( str ) {
+
   word = matchCase ? word : word.toLowerCase();
    // str = str.toLowerCase();
+
  var d = editor.ActiveDocument, s = d.selection;
    var d = editor.ActiveDocument, s = d.selection;
+
  var docu = matchCase ? d.Text : d.Text.toLowerCase();
    var dText = d.Text;
+
  var tPos = Math.min( s.GetActivePos(), s.GetAnchorPos() );
    // dText = d.Text.toLowerCase();
+
  var count = 0,  hit = 0, append = "*";
    var tPos = Math.min( s.GetActivePos(), s.GetAnchorPos() );
+
  var next = countMinimum ? word.length : 1;
    var len = str.length,  pos = 0,  count = 0, hit = 0;
+
  var pos = docu.indexOf( word );
    while ( pos >= 0 ) {
+
  while ( pos >= 0 ) {
      pos = dText.indexOf( str, pos );
+
    count ++;
      if ( pos >= 0 ) {
+
    if ( pos <= tPos ) {
        count ++;
+
      hit = count;
        if ( pos == tPos ) { hit = count; }
+
      if ( pos == tPos ) { append = ""; }
        pos += len;
 
      }
 
 
     }
 
     }
     var SeparateNum = function( num ) {
+
     pos = docu.indexOf( word, pos + next );
      return num.toString().replace( /(\d)(?=(?:\d{3})+$)/g, "$1," );
 
    }
 
    return "ヒット数:" + SeparateNum( count ) + " 件"
 
          + " ( " + SeparateNum( hit ) + " 件目 ) ";
 
 
   }
 
   }
 +
  return ( " ヒット数:" + count + " 件"
 +
          + " ( " + hit + " 件目" + append + " ) "
 +
        ).replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
 
}
 
}
 
</source>
 
</source>
 
+
<br>
  
 
== 機能強化バージョン ==
 
== 機能強化バージョン ==
  
2019/08/26 追加
+
2019/08/26 追加、2019/12/03 更新
  
[[#単独マクロバージョン|単独マクロバージョン]] に以下の機能を追加しています。
+
ヒット件数表示の [[#単独マクロバージョン|単独マクロバージョン]] に以下の機能を追加しています。
 
* 選択範囲の文字数と行数を表示
 
* 選択範囲の文字数と行数を表示
* 保存済みの文書で「すべて選択」しているときにファイルサイズを表示
+
* 選択範囲の文字列のバイト数(半角=1バイト、全角=2バイト でカウント)
 +
* 「すべて選択」しているときにファイルサイズを表示
 
* 設定項目から表示方法や検索方法などを変更可
 
* 設定項目から表示方法や検索方法などを変更可
 +
※ 動作仕様の説明は [[#能書き|ソースコード末尾]] に記載してあります。
 +
<br>
 +
 +
=== ダウンロード ===
 +
 +
2019/12/03 更新
 +
;ダウンロード >> 「[[ファイル:文字数・行数・バイト数・ヒット件数.zip]]」(アイコン入り)
 
<br>
 
<br>
※ ロースペックの PC でイベントマクロ(選択範囲が変更されたとき/遅延 0秒)として使用しても、1万行・30万文字程度の文書では編集作業のジャマにはならないようでした。<br>
 
6万行・800万文字の文書では "もたつき" が生じましたが…。
 
  
 
=== ソースコード ===
 
=== ソースコード ===
2019/08/28 更新
 
;ダウンロード >> 「[[ファイル:文字数・行数・ヒット件数.zip]]」(アイコン入り)
 
  
 
<source lang="javascript">
 
<source lang="javascript">
#title = "文字数・行数・ヒット件数(選択文字列)"
+
#title = "文字数・行数・バイト数・ヒット件数"
#tooltip = "文字数・行数・検索ヒット数表示(選択範囲の文字列)"
+
#tooltip = "文字数・行数・バイト数・選択文字列の検索ヒット数表示"
 +
// #icon = "Search[2].ico"
 
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",19
 
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",19
  
 
/**
 
/**
 
  * --------------------------------------------------------------------
 
  * --------------------------------------------------------------------
  * 文字数・行数・ヒット数
+
  * 文字数・行数・バイト数・ヒット件数(選択文字列)
  * sukemaru ( 2019/08/26 - 2019/08/28 )
+
  * sukemaru ( 2019/08/26 - 2019/12/03 )
 
  * --------------------------------------------------------------------
 
  * --------------------------------------------------------------------
 
  * 編集中の文書または選択範囲の文字数と行数をステータスバーに表示します。
 
  * 編集中の文書または選択範囲の文字数と行数をステータスバーに表示します。
 
  * 選択範囲があるときは、選択範囲の文字列の出現回数を表示します。
 
  * 選択範囲があるときは、選択範囲の文字列の出現回数を表示します。
 +
* 文字数からのバイト数の簡易計算、ファイルサイズも表示できます。
 
  *  
 
  *  
  * 選択範囲のある状態でマクロを手動で実行するか、
+
  * 任意のタイミングで手動で実行するか、
  * イベント「選択範囲が変更された時」に設定して自動で実行させる想定です。
+
  * イベント「選択範囲が変更された時」などに設定して自動で実行させる想定です。
 
  *  
 
  *  
  * ※ ソースコード末尾に動作仕様(制限事項)の説明あり。
+
  * ※ ソースコード末尾に能書き(動作仕様/制限事項)あり。
 
  */
 
  */
  
184行目: 180行目:
  
  
// ---------- ▼ 設定項目 ▼ ----------
+
// ---------- ▼ 設定項目 ▼ ---------- //
  
 
// ■ 行数のカウント方法
 
// ■ 行数のカウント方法
 
// true:論理行(改行) / false:物理行(折り返し)
 
// true:論理行(改行) / false:物理行(折り返し)
var logical = false; // 初期値: false( ← Mery 方式)
+
var logical = false; // 初期値: false(Mery 方式)
  
// ■ 選択範囲の末尾が改行記号のときの 行数のカウント方法
+
// ■ 行数のカウント での選択範囲の末尾の改行記号
 
// true:次の行頭を含めない / false:含める
 
// true:次の行頭を含めない / false:含める
var ignoreEnter = false; // 初期値: false( ← Mery 方式)
+
var ignoreEnter = false; // 初期値: false(Mery 方式)
  
// ■ 文字数のカウント方法 での改行記号 CR+LF の数え方
+
// ■ 文字数のカウント での改行記号 CR+LF の数え方
 
// true:2文字あつかい / false:1文字あつかい
 
// true:2文字あつかい / false:1文字あつかい
var countCRLF = false; // 初期値: false( ← Mery 方式)
+
var countCRLF = false; // 初期値: false(Mery 方式)
 +
 
 +
// ■ バイト数・ファイルサイズを表示
 +
// true:表示する / false:表示しない
 +
var bytesEnable = true; // 初期値: true
 +
 
 +
// ■ 文書全体の「文字数」または「行数」で動作制限
 +
// 「範囲選択なし」のときのバイト数計算をしない
 +
var limitChars = 150000; // 150,000 文字超
 +
var limitLines =  10000; //  10,000 行超
 +
 
 +
// ※ 特定のファイル名などの条件でも動作制限するなら120行目付近に記述する
 +
 
  
 
// ■ ヒット数のカウント方法
 
// ■ ヒット数のカウント方法
206行目: 214行目:
 
var countMinimum = false; // 初期値: false( ← Mery 方式)
 
var countMinimum = false; // 初期値: false( ← Mery 方式)
  
// ■ 「すべて選択」でファイルサイズを表示
 
// true:表示する / false:表示しない
 
var bytesEnable = true; // 初期値: true
 
  
 
// ■ マクロの処理の所要時間を表示
 
// ■ マクロの処理の所要時間を表示
 
// true:表示する / false:表示しない
 
// true:表示する / false:表示しない
var timerEnable = false; // 初期値: false
+
var timerEnable = true; // 初期値: false
 
 
  
/* 未保存文書のバイト数の計算用 */
 
  
 +
/* 未保存文書のファイルサイズの計算用 */
 
// ■ 文字コードの形式の指定
 
// ■ 文字コードの形式の指定
 
// "" なら文書の文字コード形式 / 指定時はその文字コード(e.g. "sjis", "utf-8")
 
// "" なら文書の文字コード形式 / 指定時はその文字コード(e.g. "sjis", "utf-8")
var encoding = ""; // 初期値: 自動
+
var enc = ""; // 初期値: ""
  
 
// ■ 改行コードの形式の指定
 
// ■ 改行コードの形式の指定
// true: CR+LF / false: CR or LF / 「d.LineEnding == 0」: 自動( ← 要 Mery 2.6.10 以上)
+
// true: CR+LF / false: CR or LF / d.LineEnding === 0: 自動( ← 要 Mery 2.6.10 以上)
var CRLF = ( d.LineEnding == 0 ); // 初期値: 自動
+
var eol = ( d.LineEnding === 0 ); // 初期値: ( d.LineEnding === 0 )
  
 
// ■ BOM コード分を加算するかの指定
 
// ■ BOM コード分を加算するかの指定
 
// true: BOM を考慮する / false: 考慮しない
 
// true: BOM を考慮する / false: 考慮しない
var BOM = false; // 初期値: false
+
var bom = false; // 初期値: false
  
// ---------- ▲ 設定項目 ▲ ----------
+
// ---------- ▲ 設定項目 ▲ ---------- //
  
  
 
var s = d.selection;
 
var s = d.selection;
var isEmpty = s.IsEmpty; // 「範囲選択なし」のフラグ
+
var fullPath = d.FullName || "";
var selAll = false; // 「すべて選択」のフラグ
+
var isEmpty = s.IsEmpty; // 「範囲選択なし」フラグ
var posMode  = logical ? mePosLogical : mePosView;
+
var selAll = false;
var lineMode = logical ? 0 : meGetLineView;
+
var dLines = d.GetLines( logical ? 0 : meGetLineView );
var dt = d.Text;
+
var dt = d.Textst = "",  statusStr = "";
var lines;
 
var st;
 
var statusStr;
 
  
// 範囲選択なしなら文書全体の文字数と行数(論理行 or 表示行)
+
// ◆ 文字数・行数(論理行 or 表示行)
if ( isEmpty ) {
+
if ( isEmpty ) { st = dt; } // 範囲選択なしなら文書全体
  st = dt;
 
  lines = d.GetLines( lineMode );
 
}
 
// 範囲選択ありなら選択範囲の文字数と行数(論理行 or 表示行)
 
 
else {
 
else {
   st = s.Text;
+
   st = s.Text; // 選択範囲
   selAll = ( st == dt );
+
   selAll = ( st == dt ); // 「すべて選択」フラグ
   lines = s.GetBottomPointY( posMode )
+
   var posMode = logical ? mePosLogical : mePosView;
        - s.GetTopPointY( posMode )
+
  var sLines = s.GetBottomPointY( posMode )
        + ( ( ignoreEnter && /[\r\n]$/.test( st ) ) ? 0 : 1 );
+
            - s.GetTopPointY( posMode )
 +
            + ( ( ignoreEnter && /[\r\n]$/.test( st ) ) ? 0 : 1 );
 
}
 
}
// 文字数( CR+LF 補正
+
// CR+LF 補正
var isCRLF = ( countCRLF && CRLF );
+
var isCRLF = ( countCRLF && eol );
 
var sLen = st.length
 
var sLen = st.length
 
         + ( isCRLF ? ( st.match( /\n/g ) || [] ).length : 0 );
 
         + ( isCRLF ? ( st.match( /\n/g ) || [] ).length : 0 );
  
/* 範囲選択なしのときは 文書全体の文字数・行数 を、
+
var charStatus = " " + sLen + " 文字";
      ありのときは 選択範囲の文字数・行数 をステータスバーに表示 */
+
var lineStatus = " ( " + ( isEmpty ? dLines : sLines ) + " 行 )";
var charStr = " " + sLen + " 文字";
+
statusStr = charStatus + lineStatus;
var lineStr = " ( " + lines + " 行 )";
 
  
statusStr = charStr + lineStr;
+
// ◆ バイト数・ファイルサイズ
 +
if ( bytesEnable ) {
 +
  var byteStatus = "",  fileSizeStatus = "";
  
// すべて選択のときはファイルサイズを取得する
+
  // ◆ 範囲選択なしのとき、大きいファイルでは文書全体のバイト数を計算しない
var fso = new ActiveXObject( "Scripting.FileSystemObject" );
+
  var limitation = (
var fileSize = ( bytesEnable && selAll )
+
      dLines    > limitLines // 文書全体の「行数」で制限
            ? d.Saved
+
  || dt.length > limitChars // 文書全体の「文字数」で制限
                ? fso.GetFile( d.FullName ).Size // ファイルプロパティから
+
// || d.Mode === "foo" // 編集モードで制限
                : CalculateBytesKs( dt, d ) // ks 版「バイト数」マクロ
+
// || fullPath === "C:\\HOGE.txt" // フルパス指定で制限
            : 0;
+
// || d.Name === "Fuga.txt" // ファイル名指定で制限
var fileSizeStr = fileSize
+
// || fullPath.match( /\\piyo\\/i ) // フォルダ名指定(正規表現)で制限
                ? " ( ファイルサイズ: " + fileSize + " バイト )"
+
  );
                : "";
 
  
/* ファイルサイズ、または選択文字列のヒット数をステータスバーに追加 */
+
  if ( isEmpty && limitation ) {
statusStr += ( isEmpty || selAll )  
+
    statusStr += "  ** Ctrl+A キーで全体のバイト数を表示 **";
          ? fileSizeStr
+
  }
          : HitStatus( st, dt, matchCase, countMinimum );
+
  // ◆ 文字数からバイト数を簡易集計(kuro 版「バイト数」マクロ)
 +
  else {
 +
    var bytes = CalculateBytesKuro( st, sLen );
 +
    byteStatus = " / " + bytes + " バイト";
 +
  }
 +
  // ◆ 「すべて選択」しているときはファイルサイズを表示
 +
  if ( selAll ) {
 +
    var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
 +
    // ファイルサイズ(ファイルシステムから取得、または ks 版「バイト数」マクロ)
 +
    var fileSize = ( d.Saved && fullPath && Fso.FileExists( fullPath ) )
 +
                ? Fso.GetFile( fullPath ).Size
 +
                : CalculateBytesKs( dt, enc, eol, bom );
 +
    fileSizeStatus = " ( ファイルサイズ: " + fileSize + " バイト )";
 +
  }
 +
  statusStr += byteStatus + fileSizeStatus;
 +
}
  
/* マクロの処理の所要時間をステータスバーに追加 */
+
// ◆ 選択範囲の文字列のヒット数
statusStr += timerEnable ? TimerElapsed( new Date(), timerStart ) : "";
+
if ( ! isEmpty && ! selAll ) {
 +
  statusStr += "  /  " + HitStatus( st, dt, matchCase, countMinimum );
 +
}
  
 +
// ◆ ステータスバーに表示
 
Status = SeparateNum( statusStr );
 
Status = SeparateNum( statusStr );
  
// --------------------------------------------------------------------
+
// ◆ マクロの処理の所要時間
 +
Status += timerEnable ? TimerElapsed( new Date(), timerStart ) : "";
 +
// Quit();
 +
 
 +
 
 +
// ---------- ▼ 関数 ▼ ---------- //
  
 
/**
 
/**
295行目: 316行目:
 
  */
 
  */
 
function SeparateNum( str ) {
 
function SeparateNum( str ) {
   return str.replace( /(\d)(?=(?:\d{3})+[^\d])/g, "$1," );
+
   return str.replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
 
}
 
}
  
310行目: 331行目:
 
  * 関数 HitStatus( strSelection, strDocuText, matchCase, countMinimum )
 
  * 関数 HitStatus( strSelection, strDocuText, matchCase, countMinimum )
 
  * 選択文字列の出現回数を返す
 
  * 選択文字列の出現回数を返す
* ※ 変数 s はグローバルスコープの Document.Selection
 
 
  */
 
  */
 
function HitStatus( word, docu, matchCase, countMinimum ) {
 
function HitStatus( word, docu, matchCase, countMinimum ) {
   var word = matchCase ? word : word.toLowerCase();
+
   docu = matchCase ? docu : docu.toLowerCase();
   var docu = matchCase ? docu : docu.toLowerCase();
+
   word = matchCase ? word : word.toLowerCase();
   var len = word.length;
+
   var s = editor.ActiveDocument.selection;
   var tPos = Math.min( s.GetActivePos(), s.GetAnchorPos() );
+
   var tPos = Math.min( s.GetActivePos(), s.GetAnchorPos() )
   var pos = 0,  count = 0, hit = 0;
+
   var count = 0,  hit = 0, append = "*";
 +
  var next = countMinimum ? word.length : 1;
 +
  var pos = docu.indexOf( word );
 
   while ( pos >= 0 ) {
 
   while ( pos >= 0 ) {
     pos = docu.indexOf( word, pos );
+
     count ++;
     if ( pos >= 0 ) {
+
     if ( pos <= tPos ) {
       count ++;
+
       hit = count;
       if ( pos == tPos ) {
+
       if ( pos == tPos ) { append = ""; }
        hit = count;
 
      }
 
      pos += countMinimum ? len : 1;
 
 
     }
 
     }
 +
    pos = docu.indexOf( word, pos + next );
 +
  }
 +
  return "ヒット数:" + count + " 件"
 +
        + " ( " + hit + " 件目" + append + " ) ";
 +
}
 +
 +
/**
 +
* 関数 CalculateBytesKuro( str, str.length )
 +
* kuro 版「バイト数」マクロのコードを関数化
 +
*/
 +
function CalculateBytesKuro( str, sLen ) {
 +
  var bytes = 0;
 +
  for ( var i = 0, c; i < sLen; i ++ ) {
 +
    c = str.charCodeAt( i );
 +
    bytes += ( ( c >= 0x0 && c < 0x81 ) || // ascii 英数字, 制御コード
 +
              ( c >= 0xff61 && c < 0xffa0 ) || // 半角カナ
 +
              ( c == 0xf8f0 ) || ( c >= 0xf8f1 && c < 0xf8f4 ) )
 +
          ? 1 : 2;
 
   }
 
   }
   return "  /  ヒット数:" + count + " 件"
+
   return bytes;
        + " ( " + hit + " 件目 ) ";
 
 
}
 
}
  
 
/**
 
/**
  * 関数 CalculateBytesKs( str, objDocu )
+
  * 関数 CalculateBytesKs( str, Encord, CRLF, BOM )
 
  * ks 版「バイト数」マクロのコードを関数化
 
  * ks 版「バイト数」マクロのコードを関数化
* ※ グローバルスコープの変数を利用する
 
 
  */
 
  */
function CalculateBytesKs( str, objDocu ) {
+
function CalculateBytesKs( str, enc, eol, bom ) {
  var dEnc = objDocu.Encoding;
+
   str = ( eol ) ? str.replace( /(?:\r|\r?\n)/g, "\r\n" ) : str;
   str = ( CRLF == true ) ? str.replace( /\r?\n/g, "\r\n" ) : str;
 
 
   var charset = "",  bytes = 0;
 
   var charset = "",  bytes = 0;
   if ( ! encoding ) {
+
   if ( ! enc ) {
 +
    var dEnc = editor.ActiveDocument.Encoding;
 
     switch ( dEnc ) {
 
     switch ( dEnc ) {
       case meEncodingUTF16LENoBOM:  case meEncodingUTF16BENoBOM:
+
       case meEncodingShiftJIScharset = "shift_jis";  break;
         bytes = str.length * 2;
+
      case meEncodingUTF8BOM:  case meEncodingUTF8NoBOM:
        return bytes;
+
         charset = "utf-8"; break;
 
       case meEncodingUTF16LEBOM:  case meEncodingUTF16LE:
 
       case meEncodingUTF16LEBOM:  case meEncodingUTF16LE:
 
       case meEncodingUTF16BEBOM:  case meEncodingUTF16BE:
 
       case meEncodingUTF16BEBOM:  case meEncodingUTF16BE:
         bytes = ( str.length * 2 ) + ( BOM ? 2 : 0 );
+
         bytes = str.length *2 + ( bom ? 2 : 0 ); return bytes;
        return bytes;
+
       case meEncodingUTF16LENoBOM:  case meEncodingUTF16BENoBOM:
       case meEncodingUTF8BOM:  case meEncodingUTF8NoBOM:
+
         bytes = str.length *2;  return bytes;
         charset = "utf-8"; break;
+
      case meEncodingUTF7:  charset = "utf-7"; break;
       case meEncodingUTF7:
+
       case meEncodingEUC:   charset = "euc-jp";  break;
        charset = "utf-7";  break;
+
      case meEncodingJIS:  charset = "iso-2022-jp";  break;
       case meEncodingEUC:
+
      case meEncodingThai:  charset = "windows-874";  break;
        charset = "euc-jp";  break;
+
       case meEncodingChineseSimplified:   charset = "gb2312";  break;
       case meEncodingJIS:
+
      case meEncodingKorean:              charset = "euc-kr";  break;
        charset = "iso-2022-jp";  break;
+
      case meEncodingChineseTraditional:  charset = "big5";  break;
       case meEncodingShiftJIS:
+
      case meEncodingCentralEuropean:  charset = "windows-1250";  break;
        charset = "sjis";  break;
+
      case meEncodingCyrillic:    charset = "windows-1251";  break;
 +
      case meEncodingWesternEuropean:  charset = "windows-1252";  break;
 +
      case meEncodingGreek:      charset = "windows-1253";  break;
 +
       case meEncodingTurkish:     charset = "windows-1254";  break;
 +
      case meEncodingHebrew:      charset = "windows-1255";  break;
 +
      case meEncodingArabic:      charset = "windows-1256";  break;
 +
       case meEncodingBaltic:     charset = "windows-1257";  break;
 +
      case meEncodingVietnamese:  charset = "windows-1258";  break;
 
     }
 
     }
 
   }
 
   }
   else { charset = encoding; }
+
   else { charset = enc; }
   var adodb = new ActiveXObject( "ADODB.Stream" );
+
   var Adodb = new ActiveXObject( "ADODB.Stream" );
   adodb.Type = 2, adodb.Charset = charset;
+
   Adodb.Type = 2; Adodb.Charset = charset;
   adodb.Open();
+
   Adodb.Open(); Adodb.WriteText( str );
  adodb.WriteText( str );
+
   bytes = Adodb.Position;
   bytes = adodb.Position;
+
   Adodb.Close();
   adodb.Close();
+
   if ( ! enc && ( dEnc == meEncodingUTF8NoBOM ||
   if ( ! encoding &&
+
       ( ! bom && dEnc == meEncodingUTF8BOM ) ) ) {
      ( dEnc == meEncodingUTF8NoBOM ||
 
       ( ! BOM && dEnc == meEncodingUTF8BOM ) ) ) {
 
 
     bytes -= 3;
 
     bytes -= 3;
 
   }
 
   }
 
   return bytes;
 
   return bytes;
 
}
 
}
 +
 +
/**
 +
* 関数 GetIniOption( key )
 +
* 引数で指定された設定項目の「値」を返す(※ ascii 値のみ)
 +
*/
 +
function GetIniOption( key ) {
 +
  // Mery.ini を探す
 +
  var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
 +
  var iniPath = editor.FullName.replace( /\.exe$/i, ".ini" );
 +
  if ( ! Fso.FileExists( iniPath ) ) {
 +
    iniPath = new ActiveXObject( "WScript.Shell" ).SpecialFolders( "APPDATA" )
 +
            + "\\Mery\\" + Fso.GetBaseName( editor.FullName ) + ".ini";
 +
  }
 +
  // Mery.ini を読み込む
 +
  var iniFile = Fso.OpenTextFile( iniPath, 1 );
 +
  var iniText = iniFile.ReadAll();
 +
  iniFile.Close();
 +
  // 項目の値を取得する
 +
  var value = RegExp( "^" + key + "=([^\\r\\n]+)$", "m" ).exec( iniText )[1];
 +
  iniText = "";
 +
  // 10進数なら Number 型で返す
 +
  return ( /^(?:0|-?[1-9][0-9]*)$/.test( value ) )
 +
        ? Number( value ) : value;
 +
}
 +
 +
 
</source>
 
</source>
   
+
  <div id="能書き"></div>
 
  /**
 
  /**
   * イベント「選択範囲が変更された時」以外にも、
+
   * イベントマクロに設定する場合は、「選択範囲が変更された時」以外にも、
 
   * 「ファイルを開いた時」「テキストが変更された時」「文字が挿入された時」
 
   * 「ファイルを開いた時」「テキストが変更された時」「文字が挿入された時」
 
   * 「アクティブな文書が変更された時」など、任意で。
 
   * 「アクティブな文書が変更された時」など、任意で。
 
   *  
 
   *  
   * ※ イベントの設定で「<b style="color:#c00;">遅延時間</b>」を適宜調整すること
+
   * ※ イベントの設定で「遅延時間」を適宜調整すること
   * (とくに「カーソルが移動した時」を適用する場合は遅延を長めに)。
+
   * (とくに「カーソルが移動した時」を適用する場合は遅延を長めに)。
 
   *  
 
   *  
 
   * 「ヒット数のカウント方法」の設定項目「大文字と小文字を区別」は、
 
   * 「ヒット数のカウント方法」の設定項目「大文字と小文字を区別」は、
 
   * 自動マーカーの設定状態(初期値:false)にあわせるのがよろしいかと。
 
   * 自動マーカーの設定状態(初期値:false)にあわせるのがよろしいかと。
   *   表示メニュー >> マーカー >> マーカーの設定... >> オプション
+
   * 表示メニュー >> マーカー >> マーカーの設定... >> オプション
 
   *  
 
   *  
 
   *  
 
   *  
 
   * ▼ '''動作仕様 / 制限事項''' ▼
 
   * ▼ '''動作仕様 / 制限事項''' ▼
 +
  *
 +
  * ※ 行数のカウント方法の設定を
 +
  *  <syntaxhighlight lang="javascript" inline>logical = ! GetIniOption( "LineColumnView" );</syntaxhighlight>
 +
  *  とすると Mery.ini から自動取得できますが、
 +
  *  このマクロをイベントマクロとして使う場合は '''true''' か '''false''' で指定してください。
 +
  *  イベントの遅延時間の設定値が小さいと、
 +
  *  INI ファイルの読みこみによる動作の遅滞やファイルシステムエラーを誘発します。
 
   *  
 
   *  
 
   * ※ 矩形選択範囲では正しく機能しません。
 
   * ※ 矩形選択範囲では正しく機能しません。
 
   *  
 
   *  
   * ※ 各設定項目で無効(false)を "Mery 方式" としているのは、
+
   * ※ 各設定項目で無効( <syntaxhighlight lang="javascript" inline>false</syntaxhighlight> )を "Mery 方式" としているのは、
 
   *    ステータスバーの中央右寄りに表示される "選択範囲" の数え方にあわせた表現です。
 
   *    ステータスバーの中央右寄りに表示される "選択範囲" の数え方にあわせた表現です。
   *    設定項目 ignoreEnter を有効(true)にしても、
+
   *    設定項目 <syntaxhighlight lang="javascript" inline>ignoreEnter = true</syntaxhighlight>  にしても、
 
   *    [https://www.haijin-boys.com/software/mery/mery-tips#1 文字数のカウント]では選択範囲末尾の改行記号を含めます。
 
   *    [https://www.haijin-boys.com/software/mery/mery-tips#1 文字数のカウント]では選択範囲末尾の改行記号を含めます。
 
   *  
 
   *  
407行目: 480行目:
 
   *    任意の項目を有効化(true)してください。
 
   *    任意の項目を有効化(true)してください。
 
   *  
 
   *  
   * ※ 「あああああ」5文字だけの文書で「ああ」を範囲選択した場合、
+
   * ※「あ<span style="background:#bfdfff;">ああ</span>ああ」5文字だけの文書で「ああ」で検索した場合、
  *    <s>このマクロではヒット数を "2件" としてカウントします</s>
+
   *    Mery の通常の検索メソッドでは "4回" ヒットします。
   *    (Mery の検索メソッドでは "4回" ヒットする)。
+
   *    また、「あ <span style="background:#bfdfff;">あ </span>」5文字だけの文書で「あ あ」を検索した場合は、
   *    また、「あ あ あ」5文字だけの文書で「あ あ」を検索した場合は、
+
   *    Mery では "2回" ヒットします。
   *    <s>"1件" とカウントします</s>(Mery の検索では "2回" ヒット)。
+
   *   このマクロでは、設定変数  <syntaxhighlight lang="javascript" inline>hitCountMinimum = true</syntaxhighlight> にすると、
   * <span style="color:#0000c0;">→ 設定変数で切り替え可能にした</span>
+
   *    選択範囲「ああ」で" ヒット数: 2件"、「あ あ」で "1件" とカウントします。
   *    <span style="color:#c00;">ただし、countMinimum = true で上の例のような範囲選択をしている場合、</span>
+
  *    ただし、 <syntaxhighlight lang="javascript" inline>hitCountMinimum = true</syntaxhighlight> で上の例のような範囲選択をしている場合、
   *    <span style="color:#c00;">「n件目」表示は不正確な値を返します。</span>
+
   *    ヒット数の "(n件目)" の表示は不正確な値を返します。
 
   *  
 
   *  
   * ※ 設定項目の bytesEnable が有効(true)で「すべて選択」状態のときのみ、
+
   * ※ 設定項目  <syntaxhighlight lang="javascript" inline>bytesEnable = true</syntaxhighlight>  で「すべて選択」状態のときのみ、
   *    <s>実体ファイルの</s>ファイルサイズを表示できます。
+
   *    実体ファイルのファイルサイズを表示できます。
   * <span style="color:#0000c0;">→ 「無題」や「未保存*」のタブでは文字数から「[[バイト数#文字コードを指定,または取得してバイト数を計算|バイト数]]」を計算するようにした</span>
+
   *   「無題」や「未保存*」のタブでは ks 氏の「[[バイト数#文字コードを指定,または取得してバイト数を計算|バイト数]]」マクロから移植した
 +
  *    コードにより、文字数からファイルサイズを計算します。
 
   *  
 
   *  
   * 「すべて選択」以外の状態でもバイト数を計算させることはできますが、
+
   * ※ 選択範囲の文字列のバイト数の簡易計算は、
   * イベントマクロとして使うには適さないので… (とくにロースペ PC では)
+
   *   kuro 氏の「[[バイト数#バイト数|バイト数]]」マクロから移植したコードを使用して
 +
  *    半角=1バイト、全角=2バイト でカウントします。
 
   */
 
   */

2019年12月3日 (火) 21:07時点における最新版

単独マクロバージョン[編集]

  • アクティブなタブの文書内から選択範囲の文字列に一致するものをカウントします。
  • ヒット件数はステータスバーに表示します。
選択範囲のある状態でマクロを手動で実行するか、「選択範囲が変更されたとき」のイベントマクロに設定して自動で実行させることができます。



設定項目: countMinimum
Mery の検索ではつねにヒットした文字列の「先頭位置より1文字うしろ」から再検索しますが、このマクロではヒットした文字列の「末尾位置」から再検索できます。


e.g.「あああああ」5文字だけの文書で「ああ」を検索した場合、このマクロでは "2件" とカウントさせることができますが、Mery の検索メソッド(次/前を検索)では "4回" ヒットします。
また、「あいあいあ」5文字だけの文書で「あいあ」を検索した場合は、このマクロでは "1件" とカウントさせることができます(Mery の検索メソッドでは "2回" ヒット)。
→ 少なくカウントする設定にした場合、「何件目」かの表示は、上の例のような範囲選択をしている場合には不正確な値を返します。


設定項目: matchCase
文字列のヒット判定では「大文字と小文字を区別する」を適用するかどうかを選択できます。



※ イベントマクロで利用する場合の処理速度を優先させるため、正規表現での検索処理が必要な「単語のみを検索する」は適用できません。
※ イベントマクロで利用する場合は「遅延時間」を適宜調整しないと、大きな文書の編集のさいに動作が "もたつく" ことがあります。

機能強化バージョン を追加(2019/08/26 → 更新 2019/12/03)

ソースコード[編集]

2019/12/03 更新

  • 全体のヒット件数のうしろに「何件目」のヒットかを追加
  • ヒット数のカウント方法を設定変数で指定
#title = "ヒット件数(選択文字列)"
#tooltip = "検索ヒット数表示(選択範囲の文字列)"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",19

/**
 * アクティブなタブの文書内から選択範囲の文字列に完全一致するものをカウントする。
 * ヒット件数はステータスバーに表示する。
 * 
 * 選択範囲のある状態でマクロを手動で実行するか
 * イベント「選択範囲が変更されたとき」に設定して自動で実行させる。
 */

var start = new Date();

// ■ 「あああああ」にたいして「ああ」のヒット数 (ture: 2 件、 false: 4 件)
var countMinimum = true;	// Mery の検索方式にあわせるなら false に

// ■ 大文字と小文字を区別するか? (ture: する、 false: しない)
var matchCase = false;

// ■ ヒット数検索の所要時間を表示するか?
var timerEnable = true;

var d = editor.ActiveDocument, s = d.selection;
var word = matchCase ? word : word.toLowerCase();

if ( word ) {
  Status = "";
  var docu = matchCase ? d.Text : d.Text.toLowerCase();
  var tPos = Math.min( s.GetActivePos(), s.GetAnchorPos() );
  var count = 0, hit = 0, append = "*";
  var next = countMinimum ? word.length : 1;
  var pos = docu.indexOf( word );
  while ( pos >= 0 ) {
    count ++;
    if ( pos <= tPos ) {
      hit = count;
      if ( pos == tPos ) { append = ""; }
    }
    pos = docu.indexOf( word, pos + next );
  }

  Status = ( " ヒット数:" + count + " 件"
             + " ( " + hit + " 件目" + append + " ) "
           ).replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
  if ( timerEnable ) {
    Status += "  [ "
            + ( ( new Date() - start ) / 1000 ).toFixed( 3 )
                                               .replace( /\./, ". " )
            + " 秒 ]";
  }
}


組み込み用関数バージョン[編集]

2019/07/20 追加、 2019/12/03 更新

  • 引数に指定した文字列の出現回数 "ヒット数:n 件 ( m 件目 ) " を返します。


※ 動作仕様・制限事項は 単独マクロバージョン に準じます。

使用例[編集]

// 選択範囲の文字列のヒット数をステータスバーの表示内容に追加
var word = document.selection.Text;
if ( word ) {
  Status += "  " + HitStatus( word, true, false );
}

組み込み関数コード[編集]

/* 
 * 関数 HitStatus( word, matchCase, countMinimum )
 * 引数に指定した文字列の出現回数 "ヒット数:n 件 ( m 件目 ) " を返す
 * 
 * 第一引数 str: 選択範囲の文字列などの「文字列」オブジェクト
 * 第二引数 matchCase: 大文字と小文字を区別するなら true、区別しないなら false
 * 第三引数 countMinimum:「あああああ」にたいして「ああ」のヒット数を
 *                        2 件とカウントするなら true、4 件とカウントするなら false
 */
function HitStatus( word, matchCase, countMinimum ) {
  word = matchCase ? word : word.toLowerCase();
  var d = editor.ActiveDocument, s = d.selection;
  var docu = matchCase ? d.Text : d.Text.toLowerCase();
  var tPos = Math.min( s.GetActivePos(), s.GetAnchorPos() );
  var count = 0,  hit = 0, append = "*";
  var next = countMinimum ? word.length : 1;
  var pos = docu.indexOf( word );
  while ( pos >= 0 ) {
    count ++;
    if ( pos <= tPos ) {
      hit = count;
      if ( pos == tPos ) { append = ""; }
    }
    pos = docu.indexOf( word, pos + next );
  }
  return ( " ヒット数:" + count + " 件"
           + " ( " + hit + " 件目" + append + " ) "
         ).replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
}


機能強化バージョン[編集]

2019/08/26 追加、2019/12/03 更新

ヒット件数表示の 単独マクロバージョン に以下の機能を追加しています。

  • 選択範囲の文字数と行数を表示
  • 選択範囲の文字列のバイト数(半角=1バイト、全角=2バイト でカウント)
  • 「すべて選択」しているときにファイルサイズを表示
  • 設定項目から表示方法や検索方法などを変更可

※ 動作仕様の説明は ソースコード末尾 に記載してあります。

ダウンロード[編集]

2019/12/03 更新

ダウンロード >> 「ファイル:文字数・行数・バイト数・ヒット件数.zip」(アイコン入り)


ソースコード[編集]

#title = "文字数・行数・バイト数・ヒット件数"
#tooltip = "文字数・行数・バイト数・選択文字列の検索ヒット数表示"
// #icon = "Search[2].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",19

/**
 * --------------------------------------------------------------------
 * 文字数・行数・バイト数・ヒット件数(選択文字列)
 * sukemaru ( 2019/08/26 - 2019/12/03 )
 * --------------------------------------------------------------------
 * 編集中の文書または選択範囲の文字数と行数をステータスバーに表示します。
 * 選択範囲があるときは、選択範囲の文字列の出現回数を表示します。
 * 文字数からのバイト数の簡易計算、ファイルサイズも表示できます。
 * 
 * 任意のタイミングで手動で実行するか、
 * イベント「選択範囲が変更された時」などに設定して自動で実行させる想定です。
 * 
 * ※ ソースコード末尾に能書き(動作仕様/制限事項)あり。
 */

var timerStart = new Date();
var d = editor.ActiveDocument;


// ---------- ▼ 設定項目 ▼ ---------- //

// ■ 行数のカウント方法
// true:論理行(改行) / false:物理行(折り返し)
var logical = false;		// 初期値: false(Mery 方式)

// ■ 行数のカウント での選択範囲の末尾の改行記号
// true:次の行頭を含めない / false:含める
var ignoreEnter = false;	// 初期値: false(Mery 方式)

// ■ 文字数のカウント での改行記号 CR+LF の数え方
// true:2文字あつかい / false:1文字あつかい
var countCRLF = false;		// 初期値: false(Mery 方式)

// ■ バイト数・ファイルサイズを表示
// true:表示する / false:表示しない
var bytesEnable = true;		// 初期値: true

// ■ 文書全体の「文字数」または「行数」で動作制限
// 「範囲選択なし」のときのバイト数計算をしない
var limitChars = 150000;	// 150,000 文字超
var limitLines =  10000;	//  10,000 行超

// ※ 特定のファイル名などの条件でも動作制限するなら120行目付近に記述する


// ■ ヒット数のカウント方法
// true:大文字と小文字を区別する / false:区別しない
var matchCase = false;		// 初期値: false( ← 自動マーカーの初期値)

// ■ 「あああああ」 5文字だけの文書で 「ああ」 を範囲選択したときのカウント方法
// true:ヒット数 2件 / false:ヒット数 4件
var countMinimum = false;	// 初期値: false( ← Mery 方式)


// ■ マクロの処理の所要時間を表示
// true:表示する / false:表示しない
var timerEnable = true;	// 初期値: false


/* 未保存文書のファイルサイズの計算用 */
// ■ 文字コードの形式の指定
// "" なら文書の文字コード形式 / 指定時はその文字コード(e.g. "sjis", "utf-8")
var enc = "";		// 初期値: ""

// ■ 改行コードの形式の指定
// true: CR+LF / false: CR or LF / d.LineEnding === 0: 自動( ← 要 Mery 2.6.10 以上)
var eol = ( d.LineEnding === 0 );	// 初期値: ( d.LineEnding === 0 )

// ■ BOM コード分を加算するかの指定
// true: BOM を考慮する / false: 考慮しない
var bom = false;	// 初期値: false

// ---------- ▲ 設定項目 ▲ ---------- //


var s = d.selection;
var fullPath = d.FullName || "";
var isEmpty = s.IsEmpty;	// 「範囲選択なし」フラグ
var selAll = false;
var dLines = d.GetLines( logical ? 0 : meGetLineView );
var dt = d.Text,  st = "",  statusStr = "";

// ◆ 文字数・行数(論理行 or 表示行)
if ( isEmpty ) { st = dt; }	// 範囲選択なしなら文書全体
else {
  st = s.Text;				// 選択範囲
  selAll = ( st == dt );	// 「すべて選択」フラグ
  var posMode = logical ? mePosLogical : mePosView;
  var sLines = s.GetBottomPointY( posMode )
             - s.GetTopPointY( posMode )
             + ( ( ignoreEnter && /[\r\n]$/.test( st ) ) ? 0 : 1 );
}
// CR+LF 補正
var isCRLF = ( countCRLF && eol );
var sLen = st.length
         + ( isCRLF ? ( st.match( /\n/g ) || [] ).length : 0 );

var charStatus = " " + sLen + " 文字";
var lineStatus = " ( " + ( isEmpty ? dLines : sLines ) + " 行 )";
statusStr = charStatus + lineStatus;

// ◆ バイト数・ファイルサイズ
if ( bytesEnable ) {
  var byteStatus = "",  fileSizeStatus = "";

  // ◆ 範囲選択なしのとき、大きいファイルでは文書全体のバイト数を計算しない
  var limitation = (
      dLines    > limitLines	// 文書全体の「行数」で制限
   || dt.length > limitChars	// 文書全体の「文字数」で制限
// || d.Mode === "foo"				// 編集モードで制限
// || fullPath === "C:\\HOGE.txt"	// フルパス指定で制限
// || d.Name === "Fuga.txt"			// ファイル名指定で制限
// || fullPath.match( /\\piyo\\/i )	// フォルダ名指定(正規表現)で制限
  );

  if ( isEmpty && limitation ) {
    statusStr += "  ** Ctrl+A キーで全体のバイト数を表示 **";
  }
  // ◆ 文字数からバイト数を簡易集計(kuro 版「バイト数」マクロ)
  else {
    var bytes = CalculateBytesKuro( st, sLen );
    byteStatus = " / " + bytes + " バイト";
  }
  // ◆ 「すべて選択」しているときはファイルサイズを表示
  if ( selAll ) {
    var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
    // ファイルサイズ(ファイルシステムから取得、または ks 版「バイト数」マクロ)
    var fileSize = ( d.Saved && fullPath && Fso.FileExists( fullPath ) )
                 ? Fso.GetFile( fullPath ).Size
                 : CalculateBytesKs( dt, enc, eol, bom );
    fileSizeStatus = " ( ファイルサイズ: " + fileSize + " バイト )";
  }
  statusStr += byteStatus + fileSizeStatus;
}

// ◆ 選択範囲の文字列のヒット数
if ( ! isEmpty && ! selAll ) {
  statusStr += "  /  " + HitStatus( st, dt, matchCase, countMinimum );
}

// ◆ ステータスバーに表示
Status = SeparateNum( statusStr );

// ◆ マクロの処理の所要時間
Status += timerEnable ? TimerElapsed( new Date(), timerStart ) : "";
// Quit();


// ---------- ▼ 関数 ▼ ---------- //

/**
 * 関数 SeparateNum( str )
 * 文字列中の数字を3ケタ区切りに
 */
function SeparateNum( str ) {
  return str.replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
}

/**
 * 関数 TimerElapsed( end, start )
 * マクロの処理の所要時間を計測
 */
function TimerElapsed( end, start ) {
  var elapsedSec = ( ( end - start ) / 1000 ).toFixed( 3 );
  return " [ " + elapsedSec.replace( /\./, ". " ) + " 秒 ]";
}

/**
 * 関数 HitStatus( strSelection, strDocuText, matchCase, countMinimum )
 * 選択文字列の出現回数を返す
 */
function HitStatus( word, docu, matchCase, countMinimum ) {
  docu = matchCase ? docu : docu.toLowerCase();
  word = matchCase ? word : word.toLowerCase();
  var s = editor.ActiveDocument.selection;
  var tPos = Math.min( s.GetActivePos(), s.GetAnchorPos() )
  var count = 0,  hit = 0, append = "*";
  var next = countMinimum ? word.length : 1;
  var pos = docu.indexOf( word );
  while ( pos >= 0 ) {
    count ++;
    if ( pos <= tPos ) {
      hit = count;
      if ( pos == tPos ) { append = ""; }
    }
    pos = docu.indexOf( word, pos + next );
  }
  return "ヒット数:" + count + " 件"
         + " ( " + hit + " 件目" + append + " ) ";
}

/**
 * 関数 CalculateBytesKuro( str, str.length )
 * kuro 版「バイト数」マクロのコードを関数化
 */
function CalculateBytesKuro( str, sLen ) {
  var bytes = 0;
  for ( var i = 0, c; i < sLen; i ++ ) {
    c = str.charCodeAt( i );
    bytes += ( ( c >= 0x0 && c < 0x81 ) ||	// ascii 英数字, 制御コード
               ( c >= 0xff61 && c < 0xffa0 ) ||	// 半角カナ
               ( c == 0xf8f0 ) || ( c >= 0xf8f1 && c < 0xf8f4 ) )
           ? 1 : 2;
  }
  return bytes;
}

/**
 * 関数 CalculateBytesKs( str, Encord, CRLF, BOM )
 * ks 版「バイト数」マクロのコードを関数化
 */
function CalculateBytesKs( str, enc, eol, bom ) {
  str = ( eol ) ? str.replace( /(?:\r|\r?\n)/g, "\r\n" ) : str;
  var charset = "",  bytes = 0;
  if ( ! enc ) {
    var dEnc = editor.ActiveDocument.Encoding;
    switch ( dEnc ) {
      case meEncodingShiftJIS:  charset = "shift_jis";  break;
      case meEncodingUTF8BOM:  case meEncodingUTF8NoBOM:
        charset = "utf-8";  break;
      case meEncodingUTF16LEBOM:  case meEncodingUTF16LE:
      case meEncodingUTF16BEBOM:  case meEncodingUTF16BE:
        bytes = str.length *2 + ( bom ? 2 : 0 );  return bytes;
      case meEncodingUTF16LENoBOM:  case meEncodingUTF16BENoBOM:
        bytes = str.length *2;  return bytes;
      case meEncodingUTF7:  charset = "utf-7";  break;
      case meEncodingEUC:   charset = "euc-jp";  break;
      case meEncodingJIS:   charset = "iso-2022-jp";  break;
      case meEncodingThai:  charset = "windows-874";  break;
      case meEncodingChineseSimplified:   charset = "gb2312";  break;
      case meEncodingKorean:              charset = "euc-kr";  break;
      case meEncodingChineseTraditional:  charset = "big5";  break;
      case meEncodingCentralEuropean:  charset = "windows-1250";  break;
      case meEncodingCyrillic:    charset = "windows-1251";  break;
      case meEncodingWesternEuropean:  charset = "windows-1252";  break;
      case meEncodingGreek:       charset = "windows-1253";  break;
      case meEncodingTurkish:     charset = "windows-1254";  break;
      case meEncodingHebrew:      charset = "windows-1255";  break;
      case meEncodingArabic:      charset = "windows-1256";  break;
      case meEncodingBaltic:      charset = "windows-1257";  break;
      case meEncodingVietnamese:  charset = "windows-1258";  break;
    }
  }
  else { charset = enc; }
  var Adodb = new ActiveXObject( "ADODB.Stream" );
  Adodb.Type = 2;  Adodb.Charset = charset;
  Adodb.Open();  Adodb.WriteText( str );
  bytes = Adodb.Position;
  Adodb.Close();
  if ( ! enc && ( dEnc == meEncodingUTF8NoBOM ||
       ( ! bom && dEnc == meEncodingUTF8BOM ) ) ) {
    bytes -= 3;
  }
  return bytes;
}

/**
 * 関数 GetIniOption( key )
 * 引数で指定された設定項目の「値」を返す(※ ascii 値のみ)
 */
function GetIniOption( key ) {
  // Mery.ini を探す
  var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
  var iniPath = editor.FullName.replace( /\.exe$/i, ".ini" );
  if ( ! Fso.FileExists( iniPath ) ) {
    iniPath = new ActiveXObject( "WScript.Shell" ).SpecialFolders( "APPDATA" )
            + "\\Mery\\" + Fso.GetBaseName( editor.FullName ) + ".ini";
  }
  // Mery.ini を読み込む
  var iniFile = Fso.OpenTextFile( iniPath, 1 );
  var iniText = iniFile.ReadAll();
  iniFile.Close();
  // 項目の値を取得する
  var value = RegExp( "^" + key + "=([^\\r\\n]+)$", "m" ).exec( iniText )[1];
  iniText = "";
  // 10進数なら Number 型で返す
  return ( /^(?:0|-?[1-9][0-9]*)$/.test( value ) )
         ? Number( value ) : value;
}
/**
 * イベントマクロに設定する場合は、「選択範囲が変更された時」以外にも、
 * 「ファイルを開いた時」「テキストが変更された時」「文字が挿入された時」
 * 「アクティブな文書が変更された時」など、任意で。
 * 
 * ※ イベントの設定で「遅延時間」を適宜調整すること
 *  (とくに「カーソルが移動した時」を適用する場合は遅延を長めに)。
 * 
 * 「ヒット数のカウント方法」の設定項目「大文字と小文字を区別」は、
 * 自動マーカーの設定状態(初期値:false)にあわせるのがよろしいかと。
 * 表示メニュー >> マーカー >> マーカーの設定... >> オプション
 * 
 * 
 * ▼ 動作仕様 / 制限事項 ▼
 * 
 * ※ 行数のカウント方法の設定を
 *   logical = ! GetIniOption( "LineColumnView" );
 *   とすると Mery.ini から自動取得できますが、
 *   このマクロをイベントマクロとして使う場合は truefalse で指定してください。
 *   イベントの遅延時間の設定値が小さいと、
 *   INI ファイルの読みこみによる動作の遅滞やファイルシステムエラーを誘発します。
 * 
 * ※ 矩形選択範囲では正しく機能しません。
 * 
 * ※ 各設定項目で無効( false )を "Mery 方式" としているのは、
 *    ステータスバーの中央右寄りに表示される "選択範囲" の数え方にあわせた表現です。
 *    設定項目 ignoreEnter = true  にしても、
 *    文字数のカウントでは選択範囲末尾の改行記号を含めます。
 * 
 * ※ 文字数のカウントでは、改行記号の
 *    CR+LF と CR と LF の区別なしに1文字として扱います( ← Mery 方式)。
 * → 設定変数で区別可能にした(※ 推奨要件: Mery ver 2.6.10 以上)
 * 
 *    よそのエディタの 表示/カウント 方式にあわせたい場合は、
 *    任意の項目を有効化(true)してください。
 * 
 * ※「あああああ」5文字だけの文書で「ああ」で検索した場合、
 *    Mery の通常の検索メソッドでは "4回" ヒットします。
 *    また、「あ あ あ」5文字だけの文書で「あ あ」を検索した場合は、
 *    Mery では "2回" ヒットします。
 *    このマクロでは、設定変数  hitCountMinimum = true  にすると、
 *    選択範囲「ああ」で" ヒット数: 2件"、「あ あ」で "1件" とカウントします。
 *    ただし、 hitCountMinimum = true  で上の例のような範囲選択をしている場合、
 *    ヒット数の "(n件目)" の表示は不正確な値を返します。
 * 
 * ※ 設定項目  bytesEnable = true  で「すべて選択」状態のときのみ、
 *    実体ファイルのファイルサイズを表示できます。
 *   「無題」や「未保存*」のタブでは ks 氏の「バイト数」マクロから移植した
 *    コードにより、文字数からファイルサイズを計算します。
 * 
 * ※ 選択範囲の文字列のバイト数の簡易計算は、
 *    kuro 氏の「バイト数」マクロから移植したコードを使用して
 *    半角=1バイト、全角=2バイト でカウントします。
 */
スポンサーリンク