任意の検索エンジンで検索 (Noah) の改良について

  1. Kuro様、Noah様 大変お世話になっております。

    Mery及び表題のマクロを非常に便利に使わせていただいております。

    任意の検索エンジンで検索 を使って、This is a pen. というような文章を
    Google翻訳(英語→日本語) 及び Weblio 英和辞典・和英辞典 にて検索
    したところ、最初の単語 This についてしか検索できませんでした。
    ひょっとしたら私の使い方がおかしいのかもしれません。

    日本語の文章は、Google翻訳(日本語→英語) で問題なく翻訳できました。

    プログラミングは初心者ですが、見よう見まねで少しだけ改良
    (と言うには僭越ですが)してみました。
    いきなりマクロライブラリに登録するには危なっかしいので、
    皆様のご試用、ご意見をいただけたら幸いです。

    コードをいきなり貼り付けてしまってすみません。他に良い方法があれば
    ご教示してください。

    /**
     * 任意の検索エンジンで検索するためのマクロ。改良版 2019/02/28
     * 
     * 選択した文字をポップアップメニューから指定した検索エンジンで検索します。
     * 文字を選択していないと動作しません。
     */
    var f = [];
    
    // ここから下に検索エンジンを定義 ------------------------------------------------------------------
    // 1:検索エンジン名, 2:検索URL(検索文字列を%1で記載)
    f[f.length] = ["Google", "https://www.google.co.jp/search?q=%1&ie=utf-8&oe=utf-8"];// selectionIndex = 1
    f[f.length] = ["Yahoo! JAPAN", "https://search.yahoo.co.jp/search?p=%1&ei=UTF-8"];// selectionIndex = 2
    f[f.length] = ["Bing", "https://www.bing.com/search?q=%1"];// selectionIndex = 3
    f[f.length] = ["Wikipedia", "https://ja.wikipedia.org/wiki/%1"];// selectionIndex = 4
    f[f.length] = ["Amazon.co.jp", "https://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Daps&field-keywords=%1"];// selectionIndex = 5
    f[f.length] = ["Twitter", "https://twitter.com/search?q=%1%20lang%3Aja"];// selectionIndex = 6
    f[f.length] = ["Google翻訳(日本語→英語)", "https://translate.google.com/translate_t?hl=ja&langpair=ja%7Cen&text=%1"];// selectionIndex = 7
    f[f.length] = ["Google翻訳(英語→日本語)", "https://translate.google.com/translate_t?hl=ja&langpair=en%7Cja&text=%1"];// selectionIndex = 8
    f[f.length] = ["Weblio 英和辞典・和英辞典", "http://ejje.weblio.jp/content/%1"];// selectionIndex = 9
    f[f.length] = ["Weblio 類語辞典", "https://thesaurus.weblio.jp/content/%1"];// selectionIndex = 10
    // ここまで-----------------------------------------------------------------------------------------
    
    // 選択中のテキストを取得
    var selectionText = document.selection.Text;
    // テキストが選択されていなければ終了
    if (selectionText == "") {
        Quit();
    }
    
    // ポップアップメニューを作成
    var menu = CreatePopupMenu();
    for (var index = 0; index < f.length; index++) {
        var def = f[index];
        menu.Add(def[0], index + 1, 0);
    }
    
    // ポップアップメニューのオープン
    var selectionIndex = menu.Track(mePosMouse);
    Alert(selectionIndex);
    // 選択されていなければ終了
    if (selectionIndex == 0) {
        Quit();
    }
    
    switch(selectionIndex) {
    	case 8:
    		// Google翻訳(英語→日本語)を選択した場合の処理
    		selectionText = textProcessForGoogleEngToJa(selectionText);
    		break;
    	case 9:
    		// Weblio 英和辞典・和英辞典を選択した場合の処理
    		selectionText = textProcessForWeblio(selectionText);
    		break;
    }
    
    // ポップアップメニューからの選択結果を取得
    var selection = f[selectionIndex - 1];
    var url = selection[1];
    // %1を置換
    var replaceUrl = url.replace(/%1/g, selectionText);
    
    // ブラウザオープン
    var Shell = new ActiveXObject("WScript.Shell");
    Shell.Run(replaceUrl);
    
    function textProcessForGoogleEngToJa(selectedText) {
    	var allWords;
    	//選択された文字列を、半角空白で区切って配列に取り込む
    	allWords = selectedText.split(" ");
    	//区切られた単語を、%20 で繋ぎ合わせる。Google翻訳(英語→日本語)の仕様に合わせるため。
    	selectedText = allWords.join("%20");
    	return selectedText;
    }
    
    function textProcessForWeblio(selectedText) {
    	var allWords;
    	//選択された文字列を、半角空白で区切って配列に取り込む
    	allWords = selectedText.split(" ");
    	//区切られた単語を、+ で繋ぎ合わせる。Weblio 英和辞典・和英辞典の仕様に合わせるため。
    	selectedText = allWords.join("+");
    	return selectedText;
    }
     |  Takeshi  |  返信
  2. すみません。チェック用の1行を削除するのを忘れておりました。

    37行目の

    Alert(selectionIndex);

    は、削除してください。

     |  Takeshi  |  返信
  3. こんにちは、横レス失礼します。

    > 最初の単語 This についてしか検索できませんでした。
    基本的に検索文字列(選択範囲)に半角空白などが含まれていると URL がそこまでで途切れてしまう、というケースだとおもいます。
    きちんと動作確認していませんが、以下の①②のように、最初の選択範囲のテキストを取得する時点で ”半角空白・タブ文字・改行コード" を %20 (半角スペース U+20 のパーセントエンコード)に全置換するのはいかがでしょうか?

    ① //ここまで------ の下を変更

    // 選択中のテキストを取得し、空白文字を %20 に置換する
    var selectionText = document.selection.Text.replace( /\s/g, "%20" );	// \s を [ \t\n] としてもよい

    ② さいごの weblio 用の関数を変更

    function textProcessForWeblio( selectedText ) {
      // 半角スペース %20 を「+」に再置換する
      return selectedText.replace( /%20/g, "+" );
    }

    ※ weblio に半角「+」を検索文字列として送りたい場合は、もとの「+」をエンコード %2B かエスケープ?する必要があるかも? とおもったら
    return selectedText.replace(/\+/g,"%2B").replace(/%20/g,"+"); だとダメ(半角スペースになってしまう)みたいなので
    return selectedText.replace(/\+/g," +").replace(/%20/g,"+"); とか (全角プラス記号)
    return selectedText.replace(/\+/g," plus ").replace(/%20/g,"+"); とか…? :(

    ※ switch(selectionIndex) 文の case:8 と、function textProcessForGoogleEngToJa(selectedText) 関数は必要でなくなります。

    ※ %1 を "ダブルクオート" で囲って送るという方法もあるかもしれませんが、検索文字列(選択範囲)にダブルクオートが含まれている場合の例外処理やエスケープ処理が煩雑になるとおもうので、
    %20 での回避策をベースにして、うまく検索できないパターンには switch() 文や replace() で個別対応していくかんじで。

    あと、フォーラムにソースコードを貼るさいは、先頭に半角で <pre>、末尾に半角で </pre> を付けて囲うと、行頭の字下げなどもきちんと反映されたコードブロックになりますよ。 :)
    また、ポップアップメニューに表示するラベルは "&Google" や "Google(&G)"、"G&oogle翻訳"、"Google和英翻訳(&J)" のようにすると「アクセラレータ(アクセスキー)」を設定できます。 …私の環境(UIフォントの都合)のばあい、全角で "Google (&G)" とするほうが見やすいようでした。 :|
    年が明けてからはマクロいじりもほとんどしていない怠惰な初心者なので、トンチンカンなことを言っているようでしたらゴメンナサイです。

     |  sukemaru  |  返信
  4. Mery をご愛用いただきありがとうございます。
    マクロの開発、ありがとうございます。そしてお疲れ様です。

    MeryWiki はみんなで協力して作り上げる Wiki という仕組みになっているので、未完成のマクロや自信のないマクロでも気軽にご投稿いただいて大丈夫ですよー。誰かが直してくれるかもしれないですし、改良してくれるかもしれないです。

    もちろん、ご質問などの目的でこのフォーラムにソースコードを貼りつけていただいても大丈夫です。

    sukemaru さんが書いてくれていますが、このフォーラムにソースコードを貼りつけるときに、半角で <pre> ~ </pre> のタグが使えるようになっていますので、ご活用いただければとおもいます。(どこにもそんな情報書かれていませんが、注意書きを書くのが面倒くさくてサボっているだけです…)

    半角空白を %20 に置き換える部分ですが、Takeshi さんの方法でも sukemaru さんの方法でも大丈夫だと思いますが、JavaScript の URL エンコードを使うこともできそうですね。

    // Google翻訳(英語→日本語)を選択した場合の処理
    selectionText = encodeURI(selectionText);

    それから、Takeshi さんの投稿のソースコードの部分、裏側から pre タグをつけておきました。

     |  Kuro  |  返信
  5. Sukemaru様 さっそくの回答誠にありがとうございました。

    > ① //ここまで------ の下を変更

    var selectionText = document.selection.Text.replace( /\s/g, "%20" );

    なるほど! こうすれば選択文字列を切ったり繋げたりせずに、一括で変換できるのですね。

    > ② さいごの weblio 用の関数を変更

    	// 半角スペース %20 を「+」に再置換する
    	return selectedText.replace( /%20/g, "+" );

    これでだいぶすっきりしました。感謝です。

    > ※ weblio に半角「+」を検索文字列として送りたい場合は(中略)
    > %20 での回避策をベースにして、うまく検索できないパターンには switch() 文や replace() で個別対応していくかんじで。

    単純な文章ならば良いのですが、英文中にもいろいろな記号があることが
    今回のマクロ作成で改めて気付かされました。Google英日翻訳では、今の所、
    改行記号は大丈夫のようですが、A & B などと &記号が
    入ると検索したい文が切れてしまうことはわかりましたので対応を考えてみます。
    他にも、シングルクォートとかダブルクォートとか、問題をはらんでいそうな
    記号が多々ありそうなので、各々の検索エンジンに対応しようと思うと例外処理が
    増えそうです。自分用のツールとしてならある程度で妥協するつもりです。

    > また、ポップアップメニューに表示するラベルは "&Google" や "Google(&G)"、"G&oogle翻訳"、"Google和英翻訳(&J)" のようにすると「アクセラレータ(アクセスキー)」を設定できます。 …私の環境(UIフォントの都合)のばあい、全角で "Google (&G)" とするほうが見やすいようでした。 :|

    おお! 「アクセラレータ(アクセスキー)」 を設定するとすごく便利になりました。感激です。ありがとうございました。

    > 年が明けてからはマクロいじりもほとんどしていない怠惰な初心者なので、トンチンカンなことを言っているようでしたらゴメンナサイです。

    これを言ってしまうと歳がバレる(あるいはまったく理解されないかも)ですが、
    はるか昔にパンチカードで FORTRAN を習った世代でして、(笑)皆様のご指導を受けつつ精進してゆきたいと思っております。今後とも宜しくお願いいたします。

     |  Takeshi  |  返信
  6. Kuro様 さっそくの返信ありがとうございました。Meryの開発、たゆまぬバージョンアップ本当にありがとうございます。

    > 誰かが直してくれるかもしれないですし、改良してくれるかもしれないです。

    さっそく sukemaru 様が示唆に富む回答をしてくださってのでとても感謝しております。

    > 半角空白を %20 に置き換える部分ですが、Takeshi さんの方法でも sukemaru さんの方法でも大丈夫だと思いますが、JavaScript の URL エンコードを使うこともできそうですね。

    URL エンコード、デコードなどについてはまったく無知でして、検索ページに文字列を書き込んで得られたページのURLをブラウザから引っ張ってきて、単に半角空白を%20に換えれば良いだろうという、ド素人の考えでした。

    selectionText = encodeURI(selectionText);

    便利な関数があるのですね!
    予約文字「/」「:」「&」「+」「=」などがある場合の例外処理は今後の宿題として、引き続き考えてみます。

    > それから、Takeshi さんの投稿のソースコードの部分、裏側から pre タグをつけておきました。

    ありがとうございました!とても見やすくなりました。

     |  Takeshi  |  返信
  7. > encodeURI()
    そういえばこの関数、以前「SPA!」をふくむURLを開きたいという人に、おすすめしたことがありましたね。
    あの時点では WScript.Shell.Run() をよく理解していなかったので OpenLink() メソッドと組みあわせてしまい対処法としてあまり確実なものにならず、その後失念してました。 :(
    (禁止文字を含む「URL文字列」を開くだけなら WScript.Shell.Run() で丸投げしてブラウザにURLエンコードさせるほうが確実っぽかったので、「開けゴマ」マクロでは encodeURI() 関数を使わずに済ませちゃいました…)

    > 例外処理は今後の宿題として
    検索エンジンごとの仕様に細かく対処対応することができるならそれが一番ではありますが、マクロをご自分用と割り切ってしまうならエンコードやエスケープで頭を悩ませるよりも、selectionText 変数とは別に

    document.selection.Copy();

    の一行を入れてクリップボードに元の文字列のまま格納しておき、ブラウザで開いた検索ページが selectionText を意図したとおりに受け取ってくれなかった場合の保険とするのがいいかもしれませんね。
    (→ うまくなかったときは、検索ページのテキストフィールドに自分でペーストし直すということで)
    あるいは、改良版マクロを Wiki に投稿する場合でも、マクロ冒頭の /** コメントドキュメント */ の部分にその旨の注釈をつけておくとか。
    WEB検索等について私自身は、Google翻訳(英和/和英)を 外部ツールに登録 → 右クリックメニューに登録 しているだけですが、やはり禁止文字がらみの失敗も多いので「あらかじめコピーしておく」ことを習慣化しています。

    さいごに蛇足かもしれませんが、ソースコードの先頭行に

    #title="任意の検索エンジンで検索"
    #tooltip="ポップアップメニューで検索エンジンを指定してブラウザで開く"

    のようにプリフィクスをつけておくと、Mery にマクロを登録したさいに [マクロ] メニューに表示されるラベルが JS ファイル名ではなく #title の文字列になります。
    ダウンロードした人(マクロの仕様に詳しくない普通の人)がマクロを登録したあとで「マクロメニューが ○○.js ばっかり…」ということになることもなくなりますので、 #title はなるべく付けておいたほうがよろしいかと。

     |  sukemaru  |  返信
  8. Takeshiさん

    ご利用ありがとうございます。

    皆様のおっしゃるとおりURLの予約文字や特殊文字(スペースとか「!」とか)をエンコードするなり置換するなりして、それでも対応しきれない検索エンジンは個別対応になるかと思います。

    基本的に自分の使用する範囲で動けばOK!のスタンスで投稿しているため、対応しきれない部分もあるかと思いますがご容赦ください。

    最後にマクロの改良は歓迎ですので、どなたでもご自由に修正なさってください(丸投げ)

     |  Noah  |  返信
  9. > > 例外処理は今後の宿題として
    > 検索エンジンごとの仕様に細かく対処対応することができるならそれが一番ではありますが、マクロをご自分用と割り切ってしまうならエンコードやエスケープで頭を悩ませるよりも、selectionText 変数とは別に、クリップボードに元の文字列のまま格納しておき、ブラウザで開いた検索ページが selectionText を意図したとおりに受け取ってくれなかった場合の保険とするのがいいかもしれませんね。
    > (→ うまくなかったときは、検索ページのテキストフィールドに自分でペーストし直すということで)

    > やはり禁止文字がらみの失敗も多いので「あらかじめコピーしておく」ことを習慣化しています。

    クリップボードへの選択文字列を取得、その後の手動ペースト処理を取り入れさせていただきました。

    > さいごに蛇足かもしれませんが、ソースコードの先頭行にプリフィクスをつけておくと、Mery にマクロを登録したさいに [マクロ] メニューに表示されるラベルが JS ファイル名ではなく #title の文字列になります。

    なるほど! #title, #tooltip などの記述にも重要な意味、機能があるのですね。いろいろと勉強になりました。ありがとうございました!

    現在、再度の改良を行っております。完成後にはまた皆様のご意見を伺いたいです。よろしくおねがいします。

     |  Takeshi  |  返信
  10. 任意の検索エンジンで検索 その2

    Sukemaru様、Kuro様、Noah様、フォーラムの皆様 お世話になっております。

    「任意の検索エンジンで検索」 のアレンジが一段落しました。

     + が含まれる検索文字列を Weblio 英和辞典・和英辞典などに送る時の対策はあきらめ、Sukemaru様お勧めのコピペ方法で対処しました。

     その他のサイト向けには、URLにおける予約文字「/」「:」「&」「+」「=」への対処のため、encodeURIComponent 関数を使ってみました。

    各検索エンジン選択のアクセスキーを、左利きの自分に合わせて左側に配置したので、自分用のツールとしては大変便利になり、翻訳などの作業がとてもはかどります。

    さらなるご指摘があればぜひお願いいたします。

    #title="任意の検索エンジンで検索 その2"
    #tooltip="ポップアップメニューで各種検索エンジンを指定し、選択文字列をブラウザで開く"
    /*
     * 選択した文字列、複数語、複数文を任意の検索エンジンで検索するためのマクロ。作成: 2019-03-19
     * Noah様作成のマクロ「任意の検索エンジンで検索」を、Sukemaru様、Kuro様、Noah様のアドバイスを受けて改良しました。
     * このマクロを起動し、ポップアップメニューから指定した検索エンジンで検索します。
     * 文字列が選択されていないと注意が表示され、動作を終わります。
     * 注意!!一部の検索エンジンでは、URLにおける予約文字「/」「:」「&」「+」「=」などへの対処がまだです!
     * 上記が原因で検索が上手く行かなかった場合、選択文字列はクリップボードに保管されていますので、
     * 手作業で検索ボックスにペーストしてください。
     */
     
    var f = [];
    // ここから下に検索エンジンを定義 ----------------------------------------------------------
    // 1:検索エンジン名、(&G)などの記述はアクセスキーの設定用です。お好みで変更してください。
    // 2:検索URL(検索文字列入る場所を%1で記載)
    f[f.length] = ["Google(&G)", "https://www.google.co.jp/search?q=%1&ie=utf-8&oe=utf-8"];// selectionIndex = 1
    f[f.length] = ["Yahoo! JAPAN(&Y)", "https://search.yahoo.co.jp/search?p=%1&ei=UTF-8"];// selectionIndex = 2
    f[f.length] = ["Bing(&B)", "https://www.bing.com/search?q=%1"];// selectionIndex = 3
    f[f.length] = ["Wikipedia 日本語版(&U)", "https://ja.wikipedia.org/wiki/%1"];// selectionIndex = 4
    f[f.length] = ["Wikipedia 英語版", "https://en.wikipedia.org/wiki/%1"];// selectionIndex = 5
    f[f.length] = ["Amazon.co.jp 全ジャンル", "https://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Daps&field-keywords=%1"];// selectionIndex = 6
    f[f.length] = ["Amazon.com 全ジャンル", "https://www.amazon.com/s?k=%1"];// selectionIndex = 7
    f[f.length] = ["Twitter", "https://twitter.com/search?q=%1%20lang%3Aja"];// selectionIndex = 8
    f[f.length] = ["Google日英翻訳(&J)", "https://translate.google.com/translate_t?hl=ja&langpair=ja%7Cen&text=%1"];// selectionIndex = 9
    f[f.length] = ["Google英日翻訳(&E)", "https://translate.google.com/translate_t?hl=ja&langpair=en%7Cja&text=%1"];// selectionIndex = 10
    f[f.length] = ["Google画像検索(&P)", "https://www.google.com/search?hl=ja&tbm=isch&source=hp&biw=1024&bih=646&ei=khV_XOe_M8-Ir7wPp9-PGA&q=%1"];// selectionIndex = 11
    f[f.length] = ["Weblio 英和和英辞典(&W)", "http://ejje.weblio.jp/content/%1"];// selectionIndex = 12
    f[f.length] = ["Weblio 英語類語辞典(&T)", "https://ejje.weblio.jp/english-thesaurus/content/%1"];// selectionIndex = 13
    f[f.length] = ["Weblio 日本語類語辞典(&R)", "https://thesaurus.weblio.jp/content/%1"];// selectionIndex = 14
    f[f.length] = ["FreeDic 英語イディオム辞典(&I)", "https://idioms.thefreedictionary.com/%1"];// selectionIndex = 15
    f[f.length] = ["FreeDic 英語類語辞典", "https://www.freethesaurus.com/%1"];// selectionIndex = 16
    f[f.length] = ["Google Map(&M)", "https://www.google.co.jp/maps/place/%1"];// selectionIndex = 17
    // ここまで-----------------------------------------------------------
    
    // 選択中の文字列、文章を取得する
    var selectionText = document.selection.Text;
    
    // 検索が上手く行かなかった場合の保険的処理として、手入力で検索ボックスにペーストするため、選択文字列をクリップボードへ保管しておく
    document.selection.Copy();
    
    // テキストが選択されていなければ終了
    if (selectionText == "") {
    	Alert("何も選択されていませんので終了します。");
    	Quit();
    }
    
    // ポップアップメニューを作成
    var menu = CreatePopupMenu();
    for (var index = 0; index < f.length; index++) {
    	var def = f[index];
    	menu.Add(def[0], index + 1, 0);
    }
    
    // ポップアップメニューのオープン、選択されていなければ終了
    var selectionIndex = menu.Track(mePosMouse);
    if (selectionIndex == 0) {
    	Quit();
    }
    
    // 各々の検索エンジンに応じた、選択文字列の処理
    switch(selectionIndex) {
    	case 2: // Yahoo! JAPAN
    	case 4: // Wikipedia 日本語
    	case 5: // Wikipedia 英語版
    	case 12: // Weblio 英和辞典・和英辞典
    	case 15: // Free Dictionary 英語イディオム辞典
    		// 半角スペース、タブのどちらかがあれば、半角 "+" 記号に置換する。
    		selectionText = selectionText.replace( /[ \t]/g, "+" );
    		break;
    	default:// その他の検索エンジンの場合
    		// URLにおける予約文字「/」「:」「&」「+」「=」などがある場合への対処のため、URLエンコード処理を行う
    		selectionText = encodeURIComponent(selectionText);
    		break;
    }
    
    // ポップアップメニューからの選択結果を取得し、それに応じた検索エンジンURLを変数 url に代入
    var selection = f[selectionIndex - 1];
    var url = selection[1];
    
    // 冒頭で定義した検索エンジンURL中の %1 を、処理後の選択文字列へと置換
    var replaceUrl = url.replace(/%1/g, selectionText);
    
    // ブラウザをオープンして、選択文字列を検索
    var Shell = new ActiveXObject("WScript.Shell");
    Shell.Run(replaceUrl);
     |  Takeshi  |  返信
  11. 検索エンジンの追加は意外と骨が折れる作業ですよね。 あと、日本語のUIでアクセラレータを適切に割りふるというのもけっこう頭が痛い部分だったりして、本当におつかれさまです。 :)
    sukemaru のポップアップメニュー系自作マクロはコードが汚いのがデフォなので、こういう読みやすいコードっていいですね。 :)

    またまた注文を付けさせていただければとおもいまして、よろしければご検討下さい。 テーマは「カスタマイズ対応」です。

    現在のコードだと、 f[f.length] = ["ラベル(&C)", "URL"]; の行を並べ替えてメニューの表示順を並べ替えたり、アイテムの追加/削除をした場合、 ID(selectionnIndex)の値が変わってしまうので、 switch(ID) { case ID: … } の case ID: をすべて書き直さなければならなくなります。

    マクロの性質上ユーザーがカスタマイズして使う前提で考え、アイテムを任意の位置に追加したり、並べ替えや削除したりにも対応できるように switch( ID ) { case ID: … } を別のかたちしたほうが扱いやすくなるとおもいます(ユーザーがメインの動作コードをいじらないで済むように)。
    以下のような代案を考えました。

    // 各々の検索エンジンに応じた、選択文字列の処理
    switch(selectionIndex) {
        case 2: // Yahoo! JAPAN
        case 4: // Wikipedia 日本語
        case 5: // Wikipedia 英語版
        case 12: // Weblio 英和辞典・和英辞典
        case 15: // Free Dictionary 英語イディオム辞典
    
    の部分を以下のように変更する
    
    /**
     * f[f.length] = ["ラベル(&K)", "URL"];  で使用した  "ラベル(&K)"  の文字列から
     * アクセラレータを除いた部分で  case "ラベル":  として
     * 文字列一致で  switch  させるコードです。
     */
    
    // メニューの検索エンジン名のラベルからアクセラレータ (&K) とアンパサンド記号 & を除去
    var label = menu.GetText( selectionIndex ).replace( /\(&.\)|&/g, "" );
    
    // 各々の検索エンジンに応じた、選択文字列の処理
    switch( label ) {
      case "Yahoo! Japan":
      case "Wikipedia 日本語版":
      case "Wikipedia 英語版":
      case "Weblio 英和和英辞典":
      case "FreeDic 英語イディオム辞典":

    検索エンジンのラベルの文字列を書きかえて使う場合は「case "ほげ": の部分も自分で書きかえてね」となりますが、書きかえる必要のある場所も分かりやすいんじゃないかな、と。

    【おまけ】 任意でポップアップメニューにセパレータ menu.Add( "", 0, meMenuSeparator ); を追加できるようにするコード。

    // 任意の位置にセパレータをはさみこむ
    f[f.length] = ["", 0, meMenuSeparator];		// セパレータ
    
    // -----------------------------
    
    // ポップアップメニューを作成
    var menu = CreatePopupMenu();
    for (var index = 0; index < f.length; index++) {
        var def = f[index];
        menu.Add(def[0], index + 1, 0);
    }
    
    の部分を以下のように変更する( f[f.length] = ["", 0, meMenuSeparator]; に対応)
    
    // ポップアップメニューを作成
    var menu = CreatePopupMenu();
    for (var index = 0; index < f.length; index++) {
        var def = f[index];
        menu.Add( def[0] , def[1] ?index + 1 :0 , def[2] ?def[2] :0 );
    }
    
    または(個人的に array[0][0] 形式が好きなので)
    
    // ポップアップメニューを作成
    var menu = CreatePopupMenu();
    for (var index = 0; index < f.length; index++) {
        // var def = f[index];
        var id = f[index][1] ? index + 1  : 0;		// URL文字列があればID、なければ 0
        var options = f[index][2] ? f[index][2] : 0;	// オプションフラグがあればフラグ、なければ 0
        menu.Add( f[index][0], id, options );
    }

    動作確認をしていただいて、うまくいくようでしたらご検討ください。 :)

    p.s. pizz 氏の GetKeyState をつかうと、修飾キーを押しながらマクロを実行したときにはポップアップメニューを出さずに「強制的に Google 検索」とかできます。

     |  sukemaru  |  返信
  12. sukemaruさんの仰る通り、検索エンジンを追加/削除したときにswitchの部分を書き換えたくないので処理方法をパラメータで渡すようにしてswitchの部分を変更しないで済むようにしました。

    #title="任意の検索エンジンで検索 その2"
    #tooltip="ポップアップメニューで各種検索エンジンを指定し、選択文字列をブラウザで開く"
    /*
     * 選択した文字列、複数語、複数文を任意の検索エンジンで検索するためのマクロ。作成: 2019-03-19
     * Noah様作成のマクロ「任意の検索エンジンで検索」を、Sukemaru様、Kuro様、Noah様のアドバイスを受けて改良しました。
     * このマクロを起動し、ポップアップメニューから指定した検索エンジンで検索します。
     * 文字列が選択されていないと注意が表示され、動作を終わります。
     * 注意!!一部の検索エンジンでは、URLにおける予約文字「/」「:」「&」「+」「=」などへの対処がまだです!
     * 上記が原因で検索が上手く行かなかった場合、選択文字列はクリップボードに保管されていますので、
     * 手作業で検索ボックスにペーストしてください。
     */
     
    var f = [];
    // ここから下に検索エンジンを定義 ----------------------------------------------------------
    // 1:検索エンジン名、(&G)などの記述はアクセスキーの設定用です。お好みで変更してください。
    // 2:検索URL(検索文字列入る場所を%1で記載)
    // 3:検索文字の処理方法(未指定:URLエンコード, 1:半角スペース、タブを"+"に置換)
    f[f.length] = ["Google(&G)", "https://www.google.co.jp/search?q=%1&ie=utf-8&oe=utf-8"];// selectionIndex = 1
    f[f.length] = ["Yahoo! JAPAN(&Y)", "https://search.yahoo.co.jp/search?p=%1&ei=UTF-8", 1];// selectionIndex = 2
    f[f.length] = ["Bing(&B)", "https://www.bing.com/search?q=%1"];// selectionIndex = 3
    f[f.length] = ["Wikipedia 日本語版(&U)", "https://ja.wikipedia.org/wiki/%1", 1];// selectionIndex = 4
    f[f.length] = ["Wikipedia 英語版", "https://en.wikipedia.org/wiki/%1", 1];// selectionIndex = 5
    f[f.length] = ["Amazon.co.jp 全ジャンル", "https://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Daps&field-keywords=%1"];// selectionIndex = 6
    f[f.length] = ["Amazon.com 全ジャンル", "https://www.amazon.com/s?k=%1"];// selectionIndex = 7
    f[f.length] = ["Twitter", "https://twitter.com/search?q=%1%20lang%3Aja"];// selectionIndex = 8
    f[f.length] = ["Google日英翻訳(&J)", "https://translate.google.com/translate_t?hl=ja&langpair=ja%7Cen&text=%1"];// selectionIndex = 9
    f[f.length] = ["Google英日翻訳(&E)", "https://translate.google.com/translate_t?hl=ja&langpair=en%7Cja&text=%1"];// selectionIndex = 10
    f[f.length] = ["Google画像検索(&P)", "https://www.google.com/search?hl=ja&tbm=isch&source=hp&biw=1024&bih=646&ei=khV_XOe_M8-Ir7wPp9-PGA&q=%1"];// selectionIndex = 11
    f[f.length] = ["Weblio 英和和英辞典(&W)", "http://ejje.weblio.jp/content/%1", 1];// selectionIndex = 12
    f[f.length] = ["Weblio 英語類語辞典(&T)", "https://ejje.weblio.jp/english-thesaurus/content/%1"];// selectionIndex = 13
    f[f.length] = ["Weblio 日本語類語辞典(&R)", "https://thesaurus.weblio.jp/content/%1"];// selectionIndex = 14
    f[f.length] = ["FreeDic 英語イディオム辞典(&I)", "https://idioms.thefreedictionary.com/%1", 1];// selectionIndex = 15
    f[f.length] = ["FreeDic 英語類語辞典", "https://www.freethesaurus.com/%1"];// selectionIndex = 16
    f[f.length] = ["Google Map(&M)", "https://www.google.co.jp/maps/place/%1"];// selectionIndex = 17
    // ここまで-----------------------------------------------------------
    
    // 選択中の文字列、文章を取得する
    var selectionText = document.selection.Text;
    
    // 検索が上手く行かなかった場合の保険的処理として、手入力で検索ボックスにペーストするため、選択文字列をクリップボードへ保管しておく
    document.selection.Copy();
    
    // テキストが選択されていなければ終了
    if (selectionText == "") {
        Alert("何も選択されていませんので終了します。");
        Quit();
    }
    
    // ポップアップメニューを作成
    var menu = CreatePopupMenu();
    for (var index = 0; index < f.length; index++) {
        var def = f[index];
        menu.Add(def[0], index + 1, 0);
    }
    
    // ポップアップメニューのオープン、選択されていなければ終了
    var selectionIndex = menu.Track(mePosMouse);
    if (selectionIndex == 0) {
        Quit();
    }
    
    // 各々の検索エンジンに応じた、選択文字列の処理
    switch(f[selectionIndex - 1][2]) {
        case 1:
            // 半角スペース、タブのどちらかがあれば、半角 "+" 記号に置換する。
            selectionText = selectionText.replace( /[ \t]/g, "+" );
            break;
        default:// その他の検索エンジンの場合
            // URLにおける予約文字「/」「:」「&」「+」「=」などがある場合への対処のため、URLエンコード処理を行う
            selectionText = encodeURIComponent(selectionText);
            break;
    }
    
    // ポップアップメニューからの選択結果を取得し、それに応じた検索エンジンURLを変数 url に代入
    var selection = f[selectionIndex - 1];
    var url = selection[1];
    
    // 冒頭で定義した検索エンジンURL中の %1 を、処理後の選択文字列へと置換
    var replaceUrl = url.replace(/%1/g, selectionText);
    
    // ブラウザをオープンして、選択文字列を検索
    var Shell = new ActiveXObject("WScript.Shell");
    Shell.Run(replaceUrl);

    あとencodeURIComponentは大体やっちゃっていいと思うのでswitchの外に出してみて、そうすると半角スペースとタブを"+"に置換する処理がいらなくなるので、現状switch自体も消せるのではないかなーと(これで対応できなくなるものがあったらすいません)。

    #title="任意の検索エンジンで検索 その2"
    #tooltip="ポップアップメニューで各種検索エンジンを指定し、選択文字列をブラウザで開く"
    /*
     * 選択した文字列、複数語、複数文を任意の検索エンジンで検索するためのマクロ。作成: 2019-03-19
     * Noah様作成のマクロ「任意の検索エンジンで検索」を、Sukemaru様、Kuro様、Noah様のアドバイスを受けて改良しました。
     * このマクロを起動し、ポップアップメニューから指定した検索エンジンで検索します。
     * 文字列が選択されていないと注意が表示され、動作を終わります。
     * 注意!!一部の検索エンジンでは、URLにおける予約文字「/」「:」「&」「+」「=」などへの対処がまだです!
     * 上記が原因で検索が上手く行かなかった場合、選択文字列はクリップボードに保管されていますので、
     * 手作業で検索ボックスにペーストしてください。
     */
     
    var f = [];
    // ここから下に検索エンジンを定義 ----------------------------------------------------------
    // 1:検索エンジン名、(&G)などの記述はアクセスキーの設定用です。お好みで変更してください。
    // 2:検索URL(検索文字列入る場所を%1で記載)
    f[f.length] = ["Google(&G)", "https://www.google.co.jp/search?q=%1&ie=utf-8&oe=utf-8"];// selectionIndex = 1
    f[f.length] = ["Yahoo! JAPAN(&Y)", "https://search.yahoo.co.jp/search?p=%1&ei=UTF-8"];// selectionIndex = 2
    f[f.length] = ["Bing(&B)", "https://www.bing.com/search?q=%1"];// selectionIndex = 3
    f[f.length] = ["Wikipedia 日本語版(&U)", "https://ja.wikipedia.org/wiki/%1"];// selectionIndex = 4
    f[f.length] = ["Wikipedia 英語版", "https://en.wikipedia.org/wiki/%1"];// selectionIndex = 5
    f[f.length] = ["Amazon.co.jp 全ジャンル", "https://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Daps&field-keywords=%1"];// selectionIndex = 6
    f[f.length] = ["Amazon.com 全ジャンル", "https://www.amazon.com/s?k=%1"];// selectionIndex = 7
    f[f.length] = ["Twitter", "https://twitter.com/search?q=%1%20lang%3Aja"];// selectionIndex = 8
    f[f.length] = ["Google日英翻訳(&J)", "https://translate.google.com/translate_t?hl=ja&langpair=ja%7Cen&text=%1"];// selectionIndex = 9
    f[f.length] = ["Google英日翻訳(&E)", "https://translate.google.com/translate_t?hl=ja&langpair=en%7Cja&text=%1"];// selectionIndex = 10
    f[f.length] = ["Google画像検索(&P)", "https://www.google.com/search?hl=ja&tbm=isch&source=hp&biw=1024&bih=646&ei=khV_XOe_M8-Ir7wPp9-PGA&q=%1"];// selectionIndex = 11
    f[f.length] = ["Weblio 英和和英辞典(&W)", "http://ejje.weblio.jp/content/%1"];// selectionIndex = 12
    f[f.length] = ["Weblio 英語類語辞典(&T)", "https://ejje.weblio.jp/english-thesaurus/content/%1"];// selectionIndex = 13
    f[f.length] = ["Weblio 日本語類語辞典(&R)", "https://thesaurus.weblio.jp/content/%1"];// selectionIndex = 14
    f[f.length] = ["FreeDic 英語イディオム辞典(&I)", "https://idioms.thefreedictionary.com/%1"];// selectionIndex = 15
    f[f.length] = ["FreeDic 英語類語辞典", "https://www.freethesaurus.com/%1"];// selectionIndex = 16
    f[f.length] = ["Google Map(&M)", "https://www.google.co.jp/maps/place/%1"];// selectionIndex = 17
    // ここまで-----------------------------------------------------------
    
    // 選択中の文字列、文章を取得する
    var selectionText = document.selection.Text;
    
    // 検索が上手く行かなかった場合の保険的処理として、手入力で検索ボックスにペーストするため、選択文字列をクリップボードへ保管しておく
    document.selection.Copy();
    
    // テキストが選択されていなければ終了
    if (selectionText == "") {
        Alert("何も選択されていませんので終了します。");
        Quit();
    }
    
    // ポップアップメニューを作成
    var menu = CreatePopupMenu();
    for (var index = 0; index < f.length; index++) {
        var def = f[index];
        menu.Add(def[0], index + 1, 0);
    }
    
    // ポップアップメニューのオープン、選択されていなければ終了
    var selectionIndex = menu.Track(mePosMouse);
    if (selectionIndex == 0) {
        Quit();
    }
    
    selectionText = encodeURIComponent(selectionText);
    
    /* 各々の検索エンジンに応じた処理があればここに記載
    switch(f[selectionIndex - 1][2]) {
        case 1:
            break;
        default:
            break;
    }
    */
    
    // ポップアップメニューからの選択結果を取得し、それに応じた検索エンジンURLを変数 url に代入
    var selection = f[selectionIndex - 1];
    var url = selection[1];
    
    // 冒頭で定義した検索エンジンURL中の %1 を、処理後の選択文字列へと置換
    var replaceUrl = url.replace(/%1/g, selectionText);
    
    // ブラウザをオープンして、選択文字列を検索
    var Shell = new ActiveXObject("WScript.Shell");
    Shell.Run(replaceUrl);
     |  Noah  |  返信
  13. sukemaru様 お忙しいところさっそくの返信ありがとうございました。

    > 検索エンジンの追加は意外と骨が折れる作業ですよね。 あと、日本語のUIでアクセラレータを適切に割りふるというのもけっこう頭が痛い部分だったりして、本当におつかれさまです。 :)

    > またまた注文を付けさせていただければとおもいまして、よろしければご検討下さい。 テーマは「カスタマイズ対応」です。

    > 【おまけ】 任意でポップアップメニューにセパレータ menu.Add( "", 0, meMenuSeparator ); を追加できるようにするコード。

     今回自分の好みで検索エンジンを追加、アクセラレータを設定してみて、非常にバグが発生しやすい作業だなと思いましたので、実にありがたいアドバイスと効果的なコードを書いていただきありがとうございました!

    さっそく取り入れさせていただき、より良いマクロにいたします。

     |  Takeshi  |  返信
  14. Noah様 さっそくの返信ありがとうございました。コードも書いていただき感謝しております。

    > sukemaruさんの仰る通り、検索エンジンを追加/削除したときにswitchの部分を書き換えたくないので処理方法をパラメータで渡すようにしてswitchの部分を変更しないで済むようにしました。

    これでかなりカスタマイズしたいユーザーに使いやすくなりました。ありがとうございました。

    > あとencodeURIComponentは大体やっちゃっていいと思うのでswitchの外に出してみて、そうすると半角スペースとタブを"+"に置換する処理がいらなくなるので、現状switch自体も消せるのではないかなーと(これで対応できなくなるものがあったらすいません)。

    僕も全部の検索エンジンで、encodeURIComponent をすれば良いのかな? と思っていたのですが、まだ検証ができてませんので、引き続きテストしてみます。

    交通量の多い赤信号を目隠しして渡っているようなプログラミングをしておりますので、エキスパートの皆様からのアドバイスがとても嬉しいです。
    今後も精進してゆきたいと思います。

     |  Takeshi  |  返信
  15. おつかれさまです。
    > > 【おまけ】 任意でポップアップメニューにセパレータ menu.Add( "", 0, meMenuSeparator ); を追加できるようにするコード。
    > さっそく取り入れさせていただき、より良いマクロにいたします。

    > > 検索エンジンを追加/削除したときにswitchの部分を書き換えたくないので処理方法をパラメータで渡すようにしてswitchの部分を変更しないで済むようにしました。
    > これでかなりカスタマイズしたいユーザーに使いやすくなりました。

    セパレータ対応のコードにする場合、"キャンセル & " という行を追加することでポップアップメニューを Space キーでキャンセルできるようになります。 Esc キーを押すよりも楽なのでキーボード派ユーザーに優しい。 :)
    <pre>
    f[f.length] = ["", 0, meMenuSeparator];
    f[f.length] = [" キャンセル & ", 0]; // & のうしろの半角空白がアクセラレータ
    </pre>
    また、Noah さんのひとつめのコード(パラメータ案)と統合するとセパレータ用の f[f.length] = ["", 0, meMenuSeparator]; のフラグ要素とバッティング(数値 1 を入れるとポップアップメニューの項目にチェックマークが付くはず。※後述)するので、そのさいには「// ポップアップメニューを作成」部分と switch 文のコードをさらに変更する必要がありますね。

    以下、ご参考まで
    <pre>
    // sukemaru のセパレータ対応のコードを一部変更
    // ラベルの文字列がなければ menu.Add() のオプションフラグ meMenuSeparator を拾う

    // e.g.1 のコードなら
    menu.Add( def[0] , def[1] ?index +1 :0, !def[0] ?def[2] :0 );

    // e.g.2 のコードなら
    var options = ! f[index][0] ? f[index][2] : 0;

    // Noah さんのひとつめのコードの switch 文を if 文で囲う

    // 各々の検索エンジンに応じた、選択文字列の処理
    if ( selectionIndex ) {
    switch ( f[selectionIndex-1][2] ) {
    case 1:
    // 【略】
    default:
    // 【略】
    }
    }
    <pre>

    ※ menu.Add( "Strings", ID, Flags ); の第3引数 Frags の定数を数値で指定する場合、以下のようになります(ビット演算らしいので 5 以上の整数値でもいずれかの効果がでることがあります)。
    1 = meMenuChecked ... チェックマークつき
    2 = meMenuGrayed ... グレーアウト(無効)にする
    3 = meMenuChecked+meMenuGrayed ... チェックマークつき & グレーアウト
    4 = meMenuSeparator ... セパレータ

    > 僕も全部の検索エンジンで、encodeURIComponent をすれば良いのかな? と思っていたのですが、まだ検証ができてませんので、引き続きテストしてみます。
    サイトごとの仕様とか、ブラウザごとの仕様とか、URLエンコードには罠がたくさんありそうですね。 :(
    がんばって素敵なマクロに仕上げてください(すでに右クリックメニューに登録させてもらっていますが) :D

     |  sukemaru  |  返信
  16. ごめんなさい、<pre>タグを閉じそこなってひどいことになってしまいました。 :(

    // sukemaru のセパレータ対応のコードを一部変更
    // ラベルの文字列がなければ menu.Add() のオプションフラグ meMenuSeparator を拾う
    
    // e.g.1 のコードなら
    menu.Add( def[0] , def[1] ?index +1 :0 , !def[0] ?def[2] :0 );
    
    // e.g.2 のコードなら
    var options = ! f[index][0] ? f[index][2] : 0;
    
    
    // Noah さんのひとつめのコードの switch 文を if 文で囲う
    
    // 各々の検索エンジンに応じた、選択文字列の処理
    if ( selectionIndex ) {
      switch ( f[selectionIndex-1][2] ) {
        case 1: 
          // 【略】
        default: 
          // 【略】
      }
    }
     |  sukemaru  |  返信
  17. マクロの開発、お疲れ様です。

    > ごめんなさい、<pre>タグを閉じそこなってひどいことになってしまいました。 :(
    あらら… ^^

    ご報告ありがとうございます。<pre> タグ機能は割と適当に実装していたので、閉じ忘れたら HTML の構文が壊れてしまうようですね。今まで気づいていなかったので助かりました。

    取り急ぎ、<pre> タグの整合性チェックのロジックを実装しておきましたので、普通に半角文字で <pre> を入力しても閉じ忘れていたら <pre> タグとして認識しないように改善しておきました。

     |  Kuro  |  返信
  18. Sukemaru様、Kuro様、Noah様、そしてフォーラムの皆様、いつもお世話になっております。

    これまでにいただいたアドバイスを反映させ、現時点でのマクロを、僭越ながら Ver 2.1 としました。
    私もまだ、使いながらの検証中ですのでいろいろ問題をはらんでいるかも知れません。

    検索エンジンの追加、順序変更がとても容易になったので、欲張ってたくさん入れ込み、左手近くのキーを脈略もなく割り付けております。あしからずご了承ください。

    ところで、ユーザーの方が新しい検索サイトを登録しようと思った場合、そのURLを "正統的" に取得する方法はあるのでしょうか? 僕は出たとこ勝負で語句を打ち込んで検索し、結果のページのURLを使うという原始的かつ野蛮な方法で調べているのですが....

    僕は Firefox を使っていますが、ブラウザによってURLが変わったりしたらお手上げです。

    あと、マクロのファイル、xxxx.js の中でインデント;字下げをする場合、タブを使うのか、何文字かの半角空白を連ねるのか、どちらが良い記法でしょうか?

    さらなるご教示をいただければ幸いです。

    #title="任意の検索エンジンで検索 Ver 2.1"
    #tooltip="ポップアップメニューで各種検索エンジンを指定し、選択文字列をブラウザで開く"
    /*
     * Ver 2.1	2019-03-23
     * 選択した文字列、複数語、複数文を任意の検索エンジンで検索するためのマクロ。
     * Noah様作成のマクロ「任意の検索エンジンで検索」を、Sukemaru様、Kuro様、Noah様のアドバイスを受けて改良しました。
     * このマクロを起動し、ポップアップメニューから指定した検索エンジンで検索します。
     * 文字列が選択されていないと注意が表示され、マクロを終わります。
     
     * 注意!!一部の検索エンジンでは、URLにおける予約文字「/」「:」「&」「+」「=」などへの対処がまだです!
     * 上記が原因で検索が上手く行かなかった場合、選択文字列はクリップボードに保管されていますので、
     * 手作業で検索ボックスにペーストしてください。
     
     * マクロ起動時に表示されるポップアップメニューは Space キーでキャンセルできます。
     */
     
    var f = [];
    // ここから下に、お好みの検索エンジンとアクセスキーを定義してください。--------------------------------
    // 1:検索エンジン名、(&G)などの記述で、G をアクセスキーとして設定できます。
    // 2:検索URL(検索文字列が入る場所を%1で記載)
    // 3:検索文字列の処理方法(未指定:URLエンコード, 1:半角スペース、タブを"+"に置換)
    //    Google フレーズ検索、Wikipedia、Weblio 英和和英辞典 などでは、複数の単語を "+" で連結して検索する必要あり!
    // ポップアップメニューの任意の位置にセパレータをはさみ込むには ["", 0, meMenuSeparator] と記述します。
    f[f.length] = ["Google(&G)", "https://www.google.co.jp/search?q=%1&ie=utf-8&oe=utf-8"];
    f[f.length] = ["Google フレーズ検索(&P)", "https://www.google.co.jp/search?q=%22%1%22&ie=utf-8&oe=utf-8", 1];
    f[f.length] = ["Yahoo! JAPAN(&Y)", "https://search.yahoo.co.jp/search?p=%1&ei=UTF-8", 1];
    f[f.length] = ["Bing", "https://www.bing.com/search?q=%1"];
    f[f.length] = ["Twitter", "https://twitter.com/search?q=%1%20lang%3Aja"];
    f[f.length] = ["", 0, meMenuSeparator];		// セパレータ
    f[f.length] = ["Wikipedia 日本語版(&U)", "https://ja.wikipedia.org/wiki/%1", 1];
    f[f.length] = ["Wikipedia 英語版(&C)", "https://en.wikipedia.org/wiki/%1", 1];
    f[f.length] = ["Amazon.co.jp 全ジャンル(&A)", "https://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Daps&field-keywords=%1"];
    f[f.length] = ["Amazon.com 全ジャンル(&D)", "https://www.amazon.com/s?k=%1"];
    f[f.length] = ["", 0, meMenuSeparator];		// セパレータ
    f[f.length] = ["Google日英翻訳(&J)", "https://translate.google.com/translate_t?hl=ja&langpair=ja%7Cen&text=%1"];
    f[f.length] = ["Google英日翻訳(&E)", "https://translate.google.com/translate_t?hl=ja&langpair=en%7Cja&text=%1"];
    f[f.length] = ["Google Books(&B)", "https://www.google.com/search?tbm=bks&q=%1"];
    f[f.length] = ["Google Map(&M)", "https://www.google.co.jp/maps/place/%1"];
    f[f.length] = ["", 0, meMenuSeparator];		// セパレータ
    f[f.length] = ["Weblio 英和和英辞典(&W)", "http://ejje.weblio.jp/content/%1", 1];
    f[f.length] = ["Weblio 英語類語辞典(&T)", "https://ejje.weblio.jp/english-thesaurus/content/%1"];
    f[f.length] = ["Weblio 日本語類語辞典(&R)", "https://thesaurus.weblio.jp/content/%1"];
    f[f.length] = ["Linguee 日英英日翻訳(&L)", "https://www.linguee.jp/%E6%97%A5%E6%9C%AC%E8%AA%9E-%E8%8B%B1%E8%AA%9E/search?source=%E8%8B%B1%E8%AA%9E&query=%1", 1];
    f[f.length] = ["", 0, meMenuSeparator];		// セパレータ
    f[f.length] = ["FreeDic 英語イディオム辞典(&I)", "https://idioms.thefreedictionary.com/%1", 1];
    f[f.length] = ["FreeDic 英語類語辞典(&Z)", "https://www.freethesaurus.com/%1"];
    f[f.length] = ["", 0, meMenuSeparator];		// セパレータ
    f[f.length] = [" キャンセル & ", 0]; 			// & のうしろの半角空白がアクセラレータ
    // ここまで-----------------------------------------------------------
    
    // 選択中の文字列、文章を取得する
    var selectionText = document.selection.Text;
    
    // 検索が上手く行かなかった場合の保険的処理として、手入力で検索ボックスにペーストするため、選択文字列をクリップボードへ保管しておく
    document.selection.Copy();
    
    // テキストが選択されていなければ終了
    if (selectionText == "") {
    	Alert("何も選択されていませんので終了します。");
    	Quit();
    }
    
    // ポップアップメニューを作成
    // ラベルの文字列がなければ menu.Add() のオプションフラグ meMenuSeparator を拾う
    var menu = CreatePopupMenu();
    for (var index = 0; index < f.length; index++) {
    	var def = f[index];
    	menu.Add( def[0] , def[1] ?index +1 :0, !def[0] ?def[2] :0 );
    }
    
    // ポップアップメニューのオープン、選択されていなければ終了
    var selectionIndex = menu.Track(mePosMouse);
    if (selectionIndex == 0) {
    	Quit();
    }
    
    // 各々の検索エンジンに応じた、選択文字列の処理
    if ( selectionIndex ) {
    	switch(f[selectionIndex - 1][2]) {
    		case 1:
    			// 半角スペース、タブのどちらかがあれば、半角 "+" 記号に置換する。
    			selectionText = selectionText.replace( /[ \t]/g, "+" );
    			break;
    		default:// その他の検索エンジンの場合
    			// URLにおける予約文字「/」「:」「&」「+」「=」などがある場合への対処のため、URLエンコード処理を行う
    			selectionText = encodeURIComponent(selectionText);
    			break;
    	}
    }
    
    // ポップアップメニューからの選択結果を取得し、それに応じた検索エンジンURLを変数 url に代入
    var selection = f[selectionIndex - 1];
    var url = selection[1];
    
    // 冒頭で定義した検索エンジンURL中の %1 を、処理後の選択文字列へと置換
    var replaceUrl = url.replace(/%1/g, selectionText);
    
    // ブラウザをオープンして、選択文字列を検索
    var Shell = new ActiveXObject("WScript.Shell");
    Shell.Run(replaceUrl);
     |  Takeshi  |  返信
  19. > 私もまだ、使いながらの検証中ですのでいろいろ問題をはらんでいるかも知れません。
    > 検索エンジンの追加、順序変更がとても容易になったので、欲張ってたくさん入れ込み
    おつかれさまです。カスタム用のサンプルコードがちゃんと意図どおりに動いたということのようで安心しました。
    カスタマイズ性があげておくと「よくできたマクロを作った」気分になれてニンマリできますよね。 :)
    すでに、十分に完成度の高いきれいなマクロだとおもいますので、動作検証に満足されたら、いよいよマクロライブラリで公開ですね!

    > ユーザーの方が新しい検索サイトを登録しようと思った場合、そのURLを "正統的" に取得する方法はあるのでしょうか?
    検索結果ページの正当な URL を手軽に取得する方法ということですよね?
    ユーザー向けの説明文に掲載できるような確実・シンプルな方法に心当たりはありません。
    ①大概は "OpenSearch" の書式に則ったものにすればよいということになるはずですが、その保証はありません。OpenSearch の仕様(英文)を読むのに抵抗がない人ならというひとつの方法ですけど、買い物系や翻訳系ではサイトごとの独自オプションが多いので、要求を満たすものではないとおもいます。
    ②検索サイトの最新の仕様に対応できてないかとおもわれますが、「Jane掲示板」の「おまいらのcommand.datを貼れ!」スレッドに検索エンジンの URL がまとめられていたこともありました。「$TEXTU」「$TEXT」などの部分を「%1」にすれば、古い書式のままであっても検索サイト側がリダイレクトしてくれることが多いので流用できるかも。
    http://jane2ch.net/test/read.cgi/community/1083605004/

    > 僕は Firefox を使っていますが、ブラウザによってURLが変わったりしたらお手上げです。
    うちも firefox なのですが、検索プラグインの保存先である search.json/search.json.mozlz4 には "OpenSearch" 的な定型書式でしか記述されていませんでした。なにかアドオンを使えば検索プラグインを旧式の XML にエクスポートして精査できるのかもしれませんが、うちは XP なので fx のバージョンが 52.…。

    > あと、マクロのファイル、xxxx.js の中でインデント;字下げをする場合、タブを使うのか、何文字かの半角空白を連ねるのか、どちらが良い記法でしょうか?
    JS では「半角空白×2」がマジョリティということらしいですが、可読性を優先して「半角空白×4」でもよろしいかとおもいます。「タブ文字」はエディタ設定でタブ幅を大きめにとっている人だと読みづらくなることがあるので、字下げが4段以上の入れ子になるようなコードには向かないとおもいます。
    うちの PC のモニターが狭いですし、ムダに長大なマクロを書いては字下げが5段以上とかやるので、拙作マクロは「半角空白×2」をデフォにしています。自作マクロ「スペース×2 追加/削除」を使いまくりでやっています。
    https://www.haijin-boys.com/wiki/字下げ・字上げ#sukemaru_版

    字下げとは関係ありませんが、拙作「検索ジャンプのinclude版」マクロでの検索性を高めるために、カッコの内側で半角空白を多用してムダに横に長くスカスカしているというのも私の自作マクロのデフォ。var s, st; などと1文字~3文字の変数をよく使うので、変数名を検索するときには余計な文字列までヒットしまくる「s」ではなく、「␣s」で検索するという小技です。

     |  sukemaru  |  返信
  20. そういえば別トピックで editors や documents の Count/Item プロパティがややこしいというという話もありましたが、このマクロのような「配列を for() 文でさばいて → ポップアップメニュー化 → 選択したコマンドを実行」という流れでも index プロパティの扱いって面倒[ ですよね。
    i.e. for() 文の 「index + 1」や switch() 文以降の「selectionIndex - 1」
    私も、手石さんの「ポップアップメニューで検索先にジャンプ」マクロの改造に着手した当初は、index の扱いに慣れていなくて四苦八苦しました。 :(

    配列やメニュー項目のインデックスを「1番からスタート」扱いに統一して「±1」を付けなくて済むかんたんな小技がありますので、よろしければ。
    ① さいしょの配列の宣言を var f = [ "" ]; として、あらかじめ f[0] に "空要素" を入れておく。
    ② for 文の変数の宣言/初期化で var index = 1; にして、f[0] への処理をスキップさせる。
    ③ それ以降の ID がらみの数値に「±1」を付ける必要がなくなる。
    ※ただし、f[n][m] の「m」は「0番からスタート」のままです。

    以下は、Takeshi さんの ver 2.1 のコードをアレンジしたものです。好き勝手に弄りまわしてゴメンナサイですが、ご参考までに。
    ・for() 文で f[0] をスキップ。
    ・セパレータの挿入方法を f[f.length] = []; に変更( "" でも可)。
    ・使い捨ての変数を削減(自分用になじみやすい変数名に書き換えちゃってます)。
    ・変数名以外の変更内容は /* 注釈 */ をつけてあります。

    var f = [];		/* f = [ "" ] なら f[0] は空要素 */
    // ここから下に、お好みの検索エンジンとアクセスキーを定義してください。--------------------------------
    
    /* f[0] はスキップさせるので、サンプル行はコメントアウト不要 */
    f[ f.length ] = [ "検索エンジン名", "https://example.com/search?q=%1", 1 ];	// 見本
      // 1:検索エンジン名、(&G) などの記述で、「G」をアクセスキーとして設定できます。
      // 2:検索URL(検索文字列が入る場所を「%1」で記述する)
      // 3:検索文字列の処理方法(未指定:URLエンコード, 1:半角スペースとタブを「+」に置換)
      //    Google フレーズ検索、Wikipedia、Weblio 英和和英辞典 などでは、複数の単語を "+" で連結して検索する必要あり!
      
    // ポップアップメニューに表示する必要のない行はコメントアウトしてください。
    // 表示する項目の並べ替え/追加/削除はご自由に。
    // f[f.length] = []; でセパレータを挿入できます。	 /* セパレータの挿入方法を変更 */ 
    
    /* Startpage.com と DuckDuckGo を追加 */ 
    f[ f.length ] = [ "Startpage(&S)", "https://www.startpage.com/do/search?q=%1" ];
    // f[ f.length ] = [ "DuckDuckGo(&D)", "https://duckduckgo.com/?q=%1&ia=web" ];
    // f[ f.length ] = [];	// セパレータ
    	/* 略 */
    f[ f.length ] = [];	// セパレータ	 /* 空配列 [] でセパレータ( "" でも可) */ 
    f[ f.length ] = [ " キャンセル & ", 0 ]; // & のうしろの半角空白がアクセラレータ(Spaceキーでキャンセル)
    // ここまで-----------------------------------------------------------
    
    /* 
    // 配列 f の内容を確認
    Alert( f.join( "\n" ).replace ( /,/g, " ,  " ).replace( /&/g, "" )
                         .replace( /^$/gm, "---- separator ----" )
                         .replace( "\n", "\n\n" ).replace( /%1/g, " 検索文字列 " )
    );
    */
    
    // 選択範囲の文字列
    var st = document.selection.Text;
    
    // 選択文字列がなければ終了
    if ( ! st ) {
      Status = "選択文字列がありません。";	/* Alert だと音がでるので Status */
      Quit();
    }
    
    // 選択文字列をクリップボードにコピー
    /* if( !st ){ Quit() } の下にする → 選択範囲がないならコピー(行コピー)なし */
    document.selection.Copy();
    
    // ポップアップメニューを作成
    var menu = CreatePopupMenu();
    
    /* var i = 1 にしてダミー要素の f[0] をスキップすると「i」とメニューのIDが一致するようになる */
    for ( var i = 1, len = f.length; i < len; i ++ ) {
    
      /* if ... else ... 文のほうが読みやすそう */
      if ( f[i].length ) {
        menu.Add( f[i][0], i );
      }
      // f[i] == [] ならセパレータ	/* f[f.length]=[] 対応バージョン */
      else {
        menu.Add( "", 0, meMenuSeparator );
      }
    }
    
    // ポップアップメニューを表示する
    var id = menu.Track( mePosMouse );
    
    // 検索サイトに応じた選択文字列の処理
    /* この if() 文の閉じカッコ位置を最終行まで下げれば if(id==0){Quit()} は不要 */
    if ( id ) {
    
      switch( f[ id ][2] ) {
        case 1:
          // 半角スペースとタブ文字を半角「+」記号に置換する
          st = st.replace( /[ \t]/g, "+" );
          break;
        default:	// その他の検索サイトの場合
          // URLエンコード処理をして、URLの予約文字「/」「:」「&」「+」「=」などに対処する
          st = encodeURIComponent( st );
          break;
      }
    
      // 検索サイトURL中の「%1」を選択文字列に置換して、検索用URLを生成する
      var url = f[ id ][1].replace( /%1/g, st );	/* 使い捨ての変数を削減 */
    
      // 検索用URLをブラウザに投げる
      new ActiveXObject("WScript.Shell").Run( url );	/* 使い捨ての変数を削減 */
    
      // 終了メッセージ
      Status = "\"" +  menu.GetText( id ).replace( /\(&.\)|&/g, "" ) + "\" で検索";
    }
     |  sukemaru  |  返信
  21. sukemaru様、フォーラムの皆様 こんにちは。

    sukemaru様、お忙しいところ、繰り返し拙いコードに手を入れていただき、さらに有意義な検索サイトも教えてくださって感謝しております。

    > そういえば別トピックで editors や documents の Count/Item プロパティがややこしいというという話もありましたが、このマクロのような「配列を for() 文でさばいて → ポップアップメニュー化 → 選択したコマンドを実行」という流れでも index プロパティの扱いって面倒[ ですよね。

    > 配列やメニュー項目のインデックスを「1番からスタート」扱いに統一して「±1」を付けなくて済むかんたんな小技がありますので、よろしければ。

    僕もインデックスでハマりました。

    以下に、アドバイスされたコードをもとに改良したコードを Ver 2.3 としてアップします。

    ただ、1点問題がありまして、ポップアップメニューをスペースキーでキャンセルしようとした場合、下記のエラーが発生します。

    場所:105行 var url = f[ id ][1].replace( /%1/g, targetText );

    「オブジェクトは 'replace' プロパティまたはメソッドをサポートしていません。」

    対症療法で、

    91行 if ( id < f.length - 1 ) {

    としたのですが、せっかくのアドバイスが台無しです。もっとスマートで根本的な解決方法があれば教えてください。いつもいつも申し訳ありません。

    #title="任意の検索エンジンで検索 Ver 2.3"
    #tooltip="ポップアップメニューで各種検索エンジンを指定し、選択文字列をブラウザで開く"
    
    /*
     * Ver 2.3	2019-03-29
     * 選択した文字列、複数語、複数文を任意の検索エンジンで検索するためのマクロ。
     * Noah様作成のマクロ「任意の検索エンジンで検索」を、Sukemaru様、Kuro様、Noah様から、* フォーラムにおける多くの助言、指導、tips などをいただき、Takeshi が改良しました。
     
     * このマクロを起動し、ポップアップメニューから指定した検索エンジンで検索します。
     * 文字列が選択されていないと注意が表示され、マクロを終わります。
     
     * 注意!!一部の検索エンジンでは、URLにおける予約文字「/」「:」「&」「+」「=」などへの対処がまだです!
     * 上記が原因で検索が上手く行かなかった場合、選択文字列はクリップボードに保管されていますので、手作業で検索ボックスにペーストしてください。
     
     * マクロ起動時に表示されるポップアップメニューは Space キーでキャンセルできます。
     */
     
    var f = [];
    // ここから下に、お好みの検索エンジンとアクセスキーを定義してください。-------
    // f[0] はスキップさせるので、この下のサンプル行はコメントアウト不要。
    f[ f.length ] = [ "検索エンジン名(&G)", "https://example.com/search?q=%1", 1 ];
    
    // 1:検索エンジン名、(&G) などの記述で、「G」をアクセスキーとして設定できます。
    // 2:検索URL(検索文字列が入る場所を「%1」で記述する)
    // 3:検索文字列の処理方法(未指定:URLエンコード, 1:半角スペースとタブを「+」に置換)
    
    //    Googleフレーズ検索、Wikipedia、Weblio 英和和英辞典 などでは、複数の単語を "+" で連結して検索する必要あり!
    // ポップアップメニューに表示する必要のない行はコメントアウトしてください。
    // 表示する項目の並べ替え/追加/削除はご自由に。
    // f[ f.length ] = []; でセパレータを挿入できます。
    f[ f.length ] = [ "Google(&G)", "https://www.google.co.jp/search?q=%1&ie=utf-8&oe=utf-8" ];
    f[ f.length ] = [ "Google フレーズ検索(&P)", "https://www.google.co.jp/search?q=%22%1%22&ie=utf-8&oe=utf-8", 1 ];
    f[ f.length ] = [ "Yahoo! JAPAN(&Y)", "https://search.yahoo.co.jp/search?p=%1&ei=UTF-8", 1 ];
    f[ f.length ] = [ "Bing", "https://www.bing.com/search?q=%1" ];
    f[ f.length ] = [ "Twitter", "https://twitter.com/search?q=%1%20lang%3Aja" ];
    f[ f.length ] = [];	// 空配列 [] でセパレータ( "" でも可)
    f[ f.length ] = [ "Wikipedia 日本語版(&U)", "https://ja.wikipedia.org/wiki/%1", 1 ];
    f[ f.length ] = [ "Wikipedia 英語版(&C)", "https://en.wikipedia.org/wiki/%1", 1 ];
    f[ f.length ] = [ "Amazon.co.jp 全ジャンル(&A)", "https://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Daps&field-keywords=%1" ];
    f[ f.length ] = [ "Amazon.com 全ジャンル(&D)", "https://www.amazon.com/s?k=%1" ];
    f[ f.length ] = [];	// セパレータ	  
    f[ f.length ] = [ "Google日英翻訳(&J)", "https://translate.google.com/translate_t?hl=ja&langpair=ja%7Cen&text=%1" ];
    f[ f.length ] = [ "Google英日翻訳(&E)", "https://translate.google.com/translate_t?hl=ja&langpair=en%7Cja&text=%1" ];
    f[ f.length ] = [ "Google Books(&B)", "https://www.google.com/search?tbm=bks&q=%1" ];
    f[ f.length ] = [ "Google Map(&M)", "https://www.google.co.jp/maps/place/%1" ];
    f[ f.length ] = [];	// セパレータ	  
    f[ f.length ] = [ "Weblio 英和和英辞典(&W)", "http://ejje.weblio.jp/content/%1", 1 ];
    f[ f.length ] = [ "Weblio 英語類語辞典(&T)", "https://ejje.weblio.jp/english-thesaurus/content/%1" ];
    f[ f.length ] = [ "Weblio 日本語類語辞典(&R)", "https://thesaurus.weblio.jp/content/%1" ];
    f[ f.length ] = [ "Linguee 日英英日翻訳(&L)", "https://www.linguee.jp/%E6%97%A5%E6%9C%AC%E8%AA%9E-%E8%8B%B1%E8%AA%9E/search?source=%E8%8B%B1%E8%AA%9E&query=%1", 1 ];
    f[ f.length ] = [];	// セパレータ	  
    f[ f.length ] = [ "FreeDic 英語イディオム辞典(&I)", "https://idioms.thefreedictionary.com/%1", 1 ];
    f[ f.length ] = [ "FreeDic 英語類語辞典(&Z)", "https://www.freethesaurus.com/%1" ];
    f[ f.length ] = [];	// セパレータ	  
    f[ f.length ] = [ "Startpage(&S)", "https://www.startpage.com/do/search?q=%1" ];
    f[ f.length ] = [ "DuckDuckGo(&D)", "https://duckduckgo.com/?q=%1&ia=web" ];
    f[ f.length ] = [];	// セパレータ	  
    f[ f.length ] = [ " キャンセル & ", 0 ]; // & のうしろの半角空白がアクセラレータ(Spaceキーでキャンセル)
    // ここまで--------------------------------------------
    
    // 選択範囲の文字列を取得
    var targetText = document.selection.Text;
    
    // 選択文字列がなければステータスバーにメッセージ表示して終了
    if ( ! targetText ) {
        Status = "選択文字列がありません。";
        Quit();
      }
      
    // 検索が上手く行かなかった場合の保険的処理として、手入力で検索ボックスにペーストするため、選択文字列をクリップボードへ保管しておく
    document.selection.Copy();
    
    // ポップアップメニューを作成
    // ラベルの文字列がなければ menu.Add() のオプションフラグ meMenuSeparator を拾う
    var menu = CreatePopupMenu();
    
    /* var i = 1 にしてダミー要素の f[0] をスキップすると「i」とメニューのIDが一致するようになる */
    for ( var i = 1, len = f.length; i < len; i ++ ) {
      if ( f[ i ].length ) {
        menu.Add( f[ i ][0], i );
      } else {
        menu.Add( "", 0, meMenuSeparator );
        // f[i] == [] ならセパレータ	 f[ f.length ]=[] 表記への対応
      }
    }
    
    // ポップアップメニューを表示する
    var id = menu.Track( mePosMouse );
    
    // 検索サイトに応じた選択文字列の処理(スペースキーが押された場合は除く)
    if ( id < f.length - 1 ) {
    
      switch( f[ id ][2] ) {
        case 1:
          // 半角スペースとタブ文字を半角「+」記号に置換する
          targetText = targetText.replace( /[ \t]/g, "+" );
          break;
        default:	// その他の検索サイトの場合
          // URLエンコード処理をして、URLの予約文字「/」「:」「&」「+」「=」などに対処する
          targetText = encodeURIComponent( targetText );
          break;
      }
    
      // ポップアップメニューの選択結果に対応して、各検索サイトURL中の「%1」を選択文字列に置換し、検索用URLを生成する
      var url = f[ id ][1].replace( /%1/g, targetText );
    
      // 検索用URLをブラウザに投げる
      new ActiveXObject("WScript.Shell").Run( url );
    
      // 終了メッセージをステータスバーに表示して終了
      Status = "\"" +  menu.GetText( id ).replace( /\(&.\)|&/g, "" ) + "\" で検索";
    }
     |  Takeshi  |  返信
  22. > ポップアップメニューをスペースキーでキャンセルしようとした場合、下記のエラーが発生します。
    > 「オブジェクトは 'replace' プロパティまたはメソッドをサポートしていません。」
    すみません。 「キャンセル」項目の ID が 0 になっていなくて switch() 文の default: に放りこまれてしまい、『 f[i][1] = 0 は String オブジェクトじゃないから replace() できないぞ、ゴルァ!! 』というエラーになるようですね。
    動作確認はしておいたつもりでしたが、「キャンセル」するときはスペースキーではなく右クリックでポップアップメニューを消すクセがついているせいで見落としてしまいました。 X(
    if ( id < f.length - 1 )  とした場合、「キャンセル」の行をコメントアウトしたり上に移動したりすると支障が出るので、以下のようなかたちにするのがよいとおもいます。 ※ switch() 文にかかるほうの if() 文の条件部分は、 if ( id ) ―― または if ( id > 0 ) ―― で。

    for ( var i = 1, len = f.length, id; i < len; i ++ ) {
      /* ↑↑↑ ① 宣言部分に id を追加 ↑↑↑ */
    
      if ( f[i].length ) {
        id = f[i][1] ? i : 0;	/* ← ② メニューの ID 用変数 */
        menu.Add( f[i][0], id );
      }
    
      /**
       * または ① ② はナシで
       *  ・f[i][1] に URL 文字列があれば「 true 」 → ID = i
       *  ・f[i][1] == 数値の 0 や、セパレータ用の空配列 [] だと「 false 」
       * という条件文にする
       *(※条件構文では 数値の 0 、空文字列 "" 、空配列 [] は、
       *  null値や undefined などと同様に false と評価される)
       */
      // Ver 2.1 と同様に…
      // if ( f[i].length ) {	// f[i] に要素があれば true (空配列 [] だけが false )
      //   menu.Add( f[i][0], f[i][1] ? i : 0 );	 // URL 文字列があれば ID = i、なければ ID = 0
      // }
    
      // コレでも大丈夫…
      // if ( f[i][1] ) {	// URL 文字列があれば true. / ["キャンセル", 0] はスキップされる
      //   menu.Add( f[i][0], i );
      // }
    
      // f[i] == [] ならセパレータ /* [] はいずれの条件文でも false になる */
      else {
        menu.Add( "", 0, meMenuSeparator );
      }
    }

    条件文を処理する速度を気にする必要もないので、3つ書き方のいずれでも問題ないでしょう。 あとからコードを見返したときに「分かりづらくならない」とおもうものを使うのがよろしいかと。
    アドバイスのつもりで余計なバグまで押し付けてしまい、すみませんでした。

     |  sukemaru  |  返信
  23. たびたびすみません。
    > コレでも大丈夫
    > if ( f[i].length )
    > menu.Add( f[i][0], f[i][1] ? i : 0 );
    > }
    は全然大丈夫じゃないです。コレでは「キャンセル」が表示されなくなってしまいますね。

     |  sukemaru  |  返信
  24. sukemaru様、こんにちは。

    繰り返し拙いコードに手を入れていただき、きれいにデバッグしてくださって感謝しております。

    僕のやり方だとエラーは消えますが、使いにくいマクロになってしまうので勉強になりました。

    Noah様のオリジナルバージョンと思うと、すごくたくさんの検索エンジンを登録してしまいましたが、貴重なアドバイス、メニューの使い方を教えていただいたので、ずいぶんとメンテナンスが楽にり、ソースコードを見てアレンジしてみようかな、と思われるユーザー様にも理解しやすくなったと感じます。(僕もですが)

    せっかく短くしていただいた変数名を、またちょっと直してしまって申し訳ありません。

    Status という便利な機能(命令?関数?)を知って感動しました。

    それと、コードの2行目に

    #tooltip="ポップアップメニューで....."

    と設定しているのですが、Mery の場合、これはどのように働くのでしょうか?
    無知で申し訳ありません。お時間のありましたら教えてください。

    以下に、Ver 2.4 としてコードをアップします。引き続きテストしてみます。

    #title="任意の検索エンジンで検索 Ver 2.4"
    #tooltip="ポップアップメニューで各種検索エンジンを指定し、選択文字列をブラウザで開く"
    
    /*
     * Ver 2.4	2019-04-02
     * 選択した文字列、複数語、複数文を任意の検索エンジンで検索するためのマクロ。
    
     * Noah様作成のマクロ「任意の検索エンジンで検索」を、Sukemaru様、Kuro様、Noah様から、* フォーラムにおける多くの助言、指導、tips などをいただき、Takeshi が改良しました。
     
     * このマクロを起動し、ポップアップメニューから指定した検索エンジンで検索します。
     * 文字列が選択されていないと注意が表示され、マクロを終わります。
     
     * 注意!!一部の検索エンジンでは、URLにおける予約文字「/」「:」「&」「+」「=」などへの対処がまだです!
     * 上記が原因で検索が上手く行かなかった場合、選択文字列はクリップボードに保管されていますので、手作業で検索ボックスにペーストしてください。
     
     * マクロ起動時に表示されるポップアップメニューは Space キーでキャンセルできます。
     */
     
    var f = [];
    // ここから下に、お好みの検索エンジンとアクセスキーを定義してください。-------
    // f[0] はスキップさせるので、この下のサンプル行はコメントアウト不要です。
    f[ f.length ] = [ "検索エンジン名", "https://example.com/search?q=%1", 1 ];
    
    // 1:検索エンジン名、(&G) などの記述で、「G」をアクセスキーとして設定できます。
    // 2:検索URL(検索文字列が入る場所を「%1」で記述する)
    // 3:検索文字列の処理方法(未指定:URLエンコード, 1:半角スペースとタブを「+」に置換。省略可)
    
    //    Google フレーズ検索、Wikipedia、Weblio 英和和英辞典 などでは、複数の単語を "+" で連結して検索する必要あり!
    // ポップアップメニューに表示する必要のない行はコメントアウトしてください。
    // 表示する項目の並べ替え/追加/削除はご自由に。
    // f[ f.length ] = []; でセパレータを挿入できます。
    f[ f.length ] = [ "Google(&G)", "https://www.google.co.jp/search?q=%1&ie=utf-8&oe=utf-8" ];
    f[ f.length ] = [ "Google フレーズ検索(&P)", "https://www.google.co.jp/search?q=%22%1%22&ie=utf-8&oe=utf-8", 1 ];
    f[ f.length ] = [ "Yahoo! JAPAN(&Y)", "https://search.yahoo.co.jp/search?p=%1&ei=UTF-8", 1 ];
    f[ f.length ] = [ "Bing", "https://www.bing.com/search?q=%1" ];
    f[ f.length ] = [ "Twitter", "https://twitter.com/search?q=%1%20lang%3Aja" ];
    f[ f.length ] = [];	// 空配列 [] でセパレータ( "" でも可)
    f[ f.length ] = [ "Wikipedia 日本語版(&U)", "https://ja.wikipedia.org/wiki/%1", 1 ];
    f[ f.length ] = [ "Wikipedia 英語版(&C)", "https://en.wikipedia.org/wiki/%1", 1 ];
    f[ f.length ] = [ "Amazon.co.jp 全ジャンル(&A)", "https://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Daps&field-keywords=%1" ];
    f[ f.length ] = [ "Amazon.com 全ジャンル(&D)", "https://www.amazon.com/s?k=%1" ];
    f[ f.length ] = [];	// セパレータ	  
    f[ f.length ] = [ "Google日英翻訳(&J)", "https://translate.google.com/translate_t?hl=ja&langpair=ja%7Cen&text=%1" ];
    f[ f.length ] = [ "Google英日翻訳(&E)", "https://translate.google.com/translate_t?hl=ja&langpair=en%7Cja&text=%1" ];
    f[ f.length ] = [ "Google Books(&B)", "https://www.google.com/search?tbm=bks&q=%1" ];
    f[ f.length ] = [ "Google Map(&M)", "https://www.google.co.jp/maps/place/%1" ];
    f[ f.length ] = [];	// セパレータ	
    f[ f.length ] = [ "Weblio 国語辞書", "https://www.weblio.jp/content/%1" ];
    f[ f.length ] = [ "Weblio 英和和英辞典(&W)", "http://ejje.weblio.jp/content/%1", 1 ];
    f[ f.length ] = [ "Weblio 英語類語辞典(&T)", "https://ejje.weblio.jp/english-thesaurus/content/%1" ];
    f[ f.length ] = [ "Weblio 日本語類語辞典(&R)", "https://thesaurus.weblio.jp/content/%1" ];
    f[ f.length ] = [ "Linguee 日英英日翻訳(&L)", "https://www.linguee.jp/%E6%97%A5%E6%9C%AC%E8%AA%9E-%E8%8B%B1%E8%AA%9E/search?source=%E8%8B%B1%E8%AA%9E&query=%1", 1 ];
    f[ f.length ] = [];	// セパレータ	  
    f[ f.length ] = [ "FreeDic 英語イディオム辞典(&I)", "https://idioms.thefreedictionary.com/%1", 1 ];
    f[ f.length ] = [ "FreeDic 英語類語辞典(&Z)", "https://www.freethesaurus.com/%1" ];
    f[ f.length ] = [];	// セパレータ	  
    f[ f.length ] = [ "Startpage(&S)", "https://www.startpage.com/do/search?q=%1" ];
    f[ f.length ] = [ "DuckDuckGo(&D)", "https://duckduckgo.com/?q=%1&ia=web" ];
    f[ f.length ] = [];	// セパレータ	  
    f[ f.length ] = [ " キャンセル & ", 0 ]; // & のうしろの半角空白がアクセラレータ(Spaceキーでキャンセル)
    // ここまで--------------------------------------------
    
    // 選択範囲の文字列を取得
    var targetText = document.selection.Text;
    
    // 文字列が選択されていなければ、ステータスバーにメッセージを表示して終了
    if ( ! targetText ) {
        Status = "選択文字列がありません!!";
        Quit();
    }
      
    // 検索が上手く行かなかった場合の保険的処理として、手入力で検索ボックスにペーストするため、選択文字列をクリップボードへ保管しておく
    document.selection.Copy();
    
    // ポップアップメニューを作成。ラベルの文字列がなければ menu.Add() のオプションフラグ meMenuSeparator を拾う
    var menu = CreatePopupMenu();
    
    /* var i = 1 にしてダミー要素の f[0] をスキップすると「i」とメニューのIDが一致するようになる */
    for ( var i = 1, len = f.length, id; i < len; i ++ ) {
    
      if ( f[ i ].length ) {
        id = f[i][1] ? i : 0; // ← メニューの ID 用変数
        menu.Add( f[ i ][0], id );
      } else {
        menu.Add( "", 0, meMenuSeparator );// f[i] == [] ならメニュー内にセパレータを表示
      }
    
    }
    
    // ポップアップメニューを表示し、選択されたメニューの id を取得する
    var id = menu.Track( mePosMouse );
    
    // 検索サイトに応じた選択文字列の処理、ポップアップメニューから戻る id により判断
    if ( id ) {
    
      switch( f[ id ][2] ) {
        case 1:
          // 検索文字列の処理方法に 1 を指定したサイトでは、半角スペースとタブ文字を半角「+」記号に置換する
          targetText = targetText.replace( /[ \t]/g, "+" );
          break;
        default:
          // その他の検索サイトでは、選択文字列を URLエンコード処理して、URLの予約文字「/」「:」「&」「+」「=」などに対処する
          targetText = encodeURIComponent( targetText );
          break;
      }
    
      // ポップアップメニューの選択結果に対応した検索サイトURL中の「%1」を選択文字列に置換し、検索用URLを生成する
      var url = f[ id ][1].replace( /%1/g, targetText );
    
      // 検索用URLをブラウザに渡してオープンする
      new ActiveXObject("WScript.Shell").Run( url );
    
      // 終了メッセージをステータスバーに表示する
      Status = "\"" +  menu.GetText( id ).replace( /\(&.\)|&/g, "" ) + "\" で検索";
    }
     |  Takeshi  |  返信
  25. おつかれさまです。
    > 僕のやり方だとエラーは消えますが、使いにくいマクロになってしまうので勉強になりました。
    > すごくたくさんの検索エンジンを登録してしまいましたが、 … ずいぶんとメンテナンスが楽にり、ソースコードを見てアレンジしてみようかな、と思われるユーザー様にも理解しやすくなったと感じます。(僕もですが)
    私も半年ちょっと前からマクロの改造・自作を始めて、いまもヨチヨチと歩んでいる最中のおなじ道ですから。 :)
    まあ、私のばあいはアレもコレもと思いつきで機能を盛っていくからコードがすごく汚らしいので、このたびはキレイにコーディングする勉強がてら手をつけさせていただきました(そもそも "自作マクロできれいにコーディングする必要はなかろう" と開き直っているのですが)。 ずけずけと勝手なことを言ってばかりの私に丁寧な返信をいただいてばかりで、こちらこそ申し訳ないぐらいです。
    動作コード部分はすでに完成しているとおもいますので、そろそろアップロードしてもよさそうですね(私自身はすでに利用させてもらっていますが)。 :)

    > #tooltip="ポップアップメニューで....."
    > と設定しているのですが、Mery の場合、これはどのように働くのでしょうか?
    「ツールチップ」は「ヒント」や「ポップアップヒント」とも呼ばれる機能で、アイコンなどにマウスポインタをのせたときに表示される、背景がクリーム色(#FFFFE1)の小さなポップアップのことです。
    Mery のツールバーのポップアップヒントでは "#tooltip の文字列" + "(ショートカットキー)" が表示されます。

    「マクロメニュー」や「マクロバー」に表示されるラベルは #title ですが、これらに加えてツールバーアイコンを指定する場合は #icon = "アイコン.ico",0 のように記述します。 ただし、Macros フォルダ以外のディレクトリにあるアイコンを指定するばあいはフルパスで記述します。
    firefox など ○○.exe のアイコンをそのまま表示させたい場合は、 #icon="c:\hoge\firefox\firefox.exe",0 なんていう指定もできますよ。
    https://www.haijin-boys.com/wiki/マクロ覚え書き(開発者向け)#プリプロセス(#title_など)
    https://www.haijin-boys.com/wiki/マテリアルデザインっぽいアイコンと『小マクロ集』

    私は Mery のウインドウ幅を 960px ぐらい、ツールバーアイコンのサイズ「中」にしている状態で、マクロバーにマクロのアイコンを 16 コ並べるために、登録したマクロ上位 16 コの #title を1文字~4文字程度に切り詰めて運用しています。 :)
    アイコンはもちろん「マテリアルデザインっぽいアイコン」。
    『小マクロ集』に掲載した半年前のスクリーンショット画像ですが、 ↓ こんな感じ ↓
    https://www.haijin-boys.com/wiki/images/9/92/Mery_スクリーンショット(1).png
    検索系マクロ向けの虫メガネのアイコンや IE / Chrome / fx / Opera などのウェブブラウザアイコン、Google 翻訳(英和/和英)アイコンなども入っているので、公式ブログで配布されている「マテリアルカラーアイコン」をお使いでしたら併せてご利用くださいませ。 (※近日中に更新予定)
    https://www.haijin-boys.com/wiki/images/f/fd/Mery用_マテリアルデザインっぽいアイコン.icl.png

     |  sukemaru  |  返信
  26. 遅ればせながら、「任意の検索エンジンで検索ー改良版」マクロの完成とマクロライブラリへの投稿、おつかれさまです&おめでとうございます。 :D
    Ver 2.4 の状態で利用させていただいていて特に不具合もないようでしたので「完成版はいつ出るのかな?」と楽しみに心待ちしていましたが … いつの間にか投稿されていたことに気付きました。
    しばらく間があいたのは動作テストと検索エンジンの拡充のためだったみたいですね。 :)

    個人的には、検索文字列(選択範囲)なしのときにもポップアップメニューが出るようにして「Google検索」のホームを開けるように改造して使っています。

    var targetText = document.selection.Text;
    
    if ( ! /\S/.test( targetText ) ) {
      targetText = "";	// 選択範囲が 空白文字・改行 だけなら → "" にする
      Status = "選択文字列がありません。";
      // Quit();
    }
    // 選択文字列をクリップボードにコピー
    // document.selection.Copy();
    
    // 検索文字列(選択範囲)がないときはグレーアウトフラグを返す
    // ※『Google(&G)』と『キャンセル』のアイテムを除外する
    var grayFlag = function( i ) {
      return ( targetText || /キャンセル|Google\(&G\)/.test( f[i][0] ) )
        ? 0 : meMenuGrayed;
    }
    
    var menu = CreatePopupMenu();
    for ( var i = 1, len = f.length, id; i < len; i ++ ) {
      if ( f[i].length ) {
        id = f[i][1] ? i : 0;
        menu.Add( f[i][0], id, grayFlag( i ) );	// グレーアウトに対応
      } else {
        menu.Add( "", 0, meMenuSeparator );
      }
    }
    var id = menu.Track( mePosMouse );
    if ( id ) {
    
      // 選択文字列をクリップボードにコピー 
      // ※キャンセルまたは文字列なしのときはコピーしない
      if ( targetText ) {
        document.selection.Copy();
      }
    
      switch( f[ id ][2] ) {
        case 1:
          targetText = targetText.replace( /[ \t]/g, "+" );
          break;
        default:
          targetText = encodeURIComponent( targetText );
          break;
      }
      var url = f[ id ][1].replace( /%1/g, targetText );
      new ActiveXObject( "WScript.Shell" ).Run( url );
      Status = " \"" +  f[ id ][0].replace( /\s*\(&.\)|&, "" ) + "\""
             + ( targetText ? " で検索" : "検索" );
    }
     |  sukemaru  |  返信
  27. 細かいですが、
    switch( f[ id ][2] ) {
    のところは、私が書くなら
    function rep(t) {
    return t.replace( /[ \t]/g, "+" );
    }
    function enc(t) {
    return encodeURIComponent( t );
    }
    var convs = [ enc, rep ];
    などとしておいて、
    t = convs[ f[ id ][2] || 0 ]( t );
    としそうです。

     |  mio  |  返信
  28. sukemaru 様

    コメントと新たな改良点のご指摘、まことにありがとうございました。

    > しばらく間があいたのは動作テストと検索エンジンの拡充のためだったみたいですね。 :)

    実は、Ver 2.4 が出来てからにわかに公私共に忙しくなったのと、
    ライブラリへの登録方法がよくわからず苦戦して、遅くなって
    しまいました。(泣)

    > 個人的には、検索文字列(選択範囲)なしのときにもポップアップメニューが出るようにして「Google検索」のホームを開けるように改造して使っています。

    投稿していただいた改良コードを勉強して、今後のバージョンに反映させていただきます。

    今は、グーグル画像検索もできるようにしようかと考えている最中です。

    残暑厳しいですが、お体には十分お気をつけください。

     |  Takeshi  |  返信
  29. mio 様

    ご指摘ありがとうございました。いろいろ工夫してくださって
    感謝しております。

    ご指摘のコードを勉強して、今後のバージョンに反映させていただきます。

    今後ともよろしくお願いいたします。

     |  Takeshi  |  返信
  30. おつかれさまです。

    > 今後のバージョンに反映させていただきます。
    あくまでも個人的に、検索文字列がないときでもブラウザで「検索エンジン」のページを開けるというのもアリな気がしたもので…。
    私の改造版だと grayFlag 変数をなくせば全てのアイテムがライブになり、検索単語なしでも各検索・辞書サイト(← かなりの項目をコメントアウトしてますが)を開けるようです。

    takeshi さんのコードでも Quit() をコメントアウトするだけで同じようになるかとおもいますが、各サイト側が空文字列だけを渡されたときにどのように反応するかは不明です。 X(

    あるいは、マクロの冒頭に動作設定用の変数を用意しておいて、検索文字列なしでもポップアップメニューを出すかどうかを選択できるようにするという方法もありますね。

    // ---------- ▼ 設定項目 ▼ ----------
    
    // ■ 検索文字列(選択範囲)がないときにポップアップメニューを表示するか?
    var emptySerchEnable = true;	//( true: 表示する / false: 表示しない)
    
    // ---------- ▲ 設定項目 ▲ ----------
    
    // var f = []; ~ ここまで----- (ry
    
    var targetText = document.selection.Text;
    
    // 設定変数 emptySerchEnable が false で、且つ
    // 文字列が選択されていなければ、ステータスバーにメッセージを表示して終了
    if ( ! targetText && ! emptySerchEnable ) {
        Status = "選択文字列がありません!!";
        Quit();
    }
    
    ~ (ry

    7月28日の私のコードで

    if ( ! /\S/.test( targetText ) ) {
      targetText = "";	// 選択範囲が 空白文字・改行 だけなら → "" にする
      Status = "選択文字列がありません。";
    }

    としているのは、「空白文字(半角スペース、タブ、改行)だけの選択範囲も "文字列なし" とみなす」という処理で、「空白以外の文字 \S がないならば」という条件文になっています。
    document.selection.Copy(); の行はポップアップメニューを表示してから「キャンセル」した場合にはクリップボードを無駄に上書きしないよう、下のほうへと移動させました。

    ※ 7月28日の私のコードで、最後の
    Status = " \"" + f[ id ][0].replace( /\s*\(&.\)|&, "" ) + "\""
    は記述ミスです。 正しくは

    Status = " \"" +  f[ id ][0].replace( /\s*\(&.\)|&/g, "" ) + "\""

    で、3月23日のコードの menu.GetText( id ).replace( ... ) に \s* を足しただけ。

    ※ ちなみに私のXPでは、"キャンセル & " のラベルを "キャンセル\t& " とすると、メニューの「キャンセル」のうしろに下線が表示されなくなります。 :)

     |  sukemaru  |  返信
スポンサーリンク