◀マクロトップへ
  • 546 直前の閉じていない HTML/XML タグを閉じる
    • 547 要手動修正
    • 549 Re:直前の閉じていない HTML/XML タグを閉じる
      • 550 Re2:直前の閉じていない HTML/XML タグを閉じる
        • 551 Re3:直前の閉じていない HTML/XML タグを閉じる
  • [546] 直前の閉じていない HTML/XML タグを閉じる gis_dur 2012年02月04日 11:21

    コツコツバージョンアップし続けていたものをリリースします。
    今も需要あるかなあ?

    /**********************************************************
    ** Close Last Tag 3.0 **
    ***********************************************************
    ** A "Sakura-Editor Macro" using WSH 5.6 **
    ** For sakura.exe ver.1.6.2.0 and over **
    ** zlib/libpng ライセンス **
    ** Copyright (C) 2004-2012 gis_dur **
    ***********************************************************
    **【動作】 **
    ** カーソル位置より前にある HTML/XML タグを **
    ** ファイル先頭に向かって検索し、 **
    ** 1. 終了タグのない開始タグ **
    ** 2. 閉じていないHTMLコメント <!-- --> **
    ** 3. 閉じていないCDATAブロック <![CDATA[ ]]> **
    ** 4. 閉じていないJSPスクリプトレット <% %> **
    ** 5. 閉じていないJSPコメント <%-- --%> **
    ** がある場合、対応する終了タグを挿入します。 **
    ** コメントタグ内は無視します。 **
    **********************************************************/

    // サクラエディタ unicode 版の場合は true にする
    var UNICODE_VER = true;
    // xml モード(大文字・小文字を区別する)
    var XML_MODE = false;
    // 挿入した閉じタグの後ろにカーソルを移動するかどうか
    var MOVE_CURSOR = true;
    // 閉じタグを省略可能な要素名
    var NO_CLOSE_TAG = "," +
    [
    "area", "base", "basefont", "bgsound", "br",
    "col", "embed", "frame", "hr", "img",
    "input", "isindex", "keygen", "link", "meta",
    "nextid", "param", "spacer", "wbr"
    ].join(",") + ",";

    /*********************************************************/

    // シェル
    if (typeof(Shell) == "undefined") {
    Shell = new ActiveXObject("WScript.Shell");
    }

    // 文字列拡張
    if (typeof(String.prototype.is_wide) == "undefined") {
    String.prototype.is_wide = function() {
    if (UNICODE_VER) return false;
    if (this.length == 0) return false;
    var c = (this.length == 1) ? this : this.charAt(0);
    return (!c.match(/[ア-ンァィゥェォッャュョ゛゜ー、。「」・]/) && escape(c).length >= 4);
    };
    }

    (function() {
    if (!XML_MODE) {
    NO_CLOSE_TAG = NO_CLOSE_TAG.toUpperCase();
    }
    // タグを表す正規表現
    var TAG_CHARS = "s!\"#$%&\'()=~|^\\`{+*}<>?@[;],/";
    (function(){
    var tmp = "";
    for (var i=0; i<TAG_CHARS.length; i++) {
    tmp += "\\"+TAG_CHARS.charAt(i);
    }
    TAG_CHARS = "[^"+tmp+"]+";
    })();
    var TAGS_EXPRESSION = new RegExp();
    TAGS_EXPRESSION.compile("<!--|-->|<!\\[CDATA\\[|\\]\\]>|<%--|--%>|<%|%>|<"+TAG_CHARS+"([^>]*/>)?|<\\/"+TAG_CHARS+"", "g");

    // データ
    var stack = new Array();
    var ins_text = "";
    var err_text = "";

    // ステート
    var is_comment = false;
    var is_cdata = false;
    var is_jsp_comment = false;
    var is_jsp = false;
    var is_error = false;

    // テキストをすべて取得
    Editor.CancelMode(0);
    var cursorX = Number(Editor.ExpandParameter('$x')) - 1;
    var cursorY = Number(Editor.ExpandParameter('$y')) - 1;
    Editor.SelectAll(0);
    var all_text = Editor.GetSelectedString(0);
    Editor.CancelMode(0);

    // 改行を統一
    all_text = all_text.replace(/\r\n|\r|\n/g, "\n");
    var all_lines = all_text.split("\n");
    var num_lines = all_lines.length;

    // カーソル以前のテキストをすべて取得
    var tmp_text = all_lines[cursorY];
    if (tmp_text == null) {
    tmp_text = "";
    }
    if (num_lines-(cursorY+1) > 0) {
    all_lines.splice(cursorY+1, num_lines-(cursorY+1));
    }
    for (var i=0; i<cursorX; i++) {
    if (tmp_text.charAt(i).is_wide()) {
    cursorX--;
    }
    }
    all_lines[cursorY] = tmp_text.substring(0, cursorX);

    // タグを取得
    var all_tags = all_lines.join(" ").match(TAGS_EXPRESSION);
    var num_tags = (all_tags == null)? 0: all_tags.length;

    // 直前の開始タグを検索
    for (var i=num_tags-1; i>=0; i--) {
    // タグ文字列取得
    var now_text = all_tags[i];
    if (!XML_MODE) {
    now_text = now_text.toUpperCase();
    }

    // 特殊なステートにある場合
    if (is_comment) {
    if (now_text == "<!--") {
    is_comment = false;
    }
    continue;
    }
    else if (is_cdata) {
    if (now_text == "<![CDATA[") {
    is_cdata = false;
    }
    continue;
    }
    else if (is_jsp_comment) {
    if (now_text == "<%--") {
    is_jsp_comment = false;
    }
    continue;
    }
    else if (is_jsp) {
    if (now_text == "<%") {
    is_jsp = false;
    }
    continue;
    }

    // 特殊なステートに遷移する場合
    if (now_text == "-->") {
    is_comment = true;
    continue;
    }
    else if (now_text == "<!--") {
    ins_text = "-->";
    break;
    }
    else if (now_text == "]]>") {
    is_cdata = true;
    continue;
    }
    else if (now_text == "<![CDATA[") {
    ins_text = "]]>";
    break;
    }
    else if (now_text == "--%>") {
    is_jsp_comment = true;
    continue;
    }
    else if (now_text == "<%--") {
    ins_text = "--%>";
    break;
    }
    else if (now_text == "%>") {
    is_jsp = true;
    continue;
    }
    else if (now_text == "<%") {
    ins_text = "%>";
    break;
    }
    // 閉じタグ不要
    else if (now_text.indexOf("/>") != -1) {
    continue;
    }
    // 閉じタグのスタックに追加
    else if (now_text.indexOf("</") == 0) {
    now_text = now_text.substring(2);
    stack.push(now_text);
    continue;
    }

    // 要素名取得
    now_text = now_text.substring(1);

    // 省略可能なタグの場合
    if (NO_CLOSE_TAG.indexOf(","+now_text+",") != -1) {
    if (stack.length == 0) {
    continue;
    }
    else {
    tmp_text = stack.pop();
    if (now_text != tmp_text) {
    stack.push(tmp_text);
    }
    continue;
    }
    }
    // 通常のタグの場合
    else {
    if (stack.length == 0) {
    ins_text = "</" + all_tags[i].substring(1) + ">";
    break;
    }
    else {
    tmp_text = stack.pop();
    if (now_text != tmp_text) {
    is_error = true;
    err_text += "タグの包含関係が不正です。\r\n";
    err_text += "<"+now_text+"> ... ... </"+tmp_text+">\r\n";
    stack = new Array();
    break;
    }
    }
    }
    }

    // コメント中
    if (is_comment) {
    is_error = true;
    err_text += "コメントの開閉関係が不正です。\r\n";
    }
    // CDATA 中
    else if (is_cdata) {
    is_error = true;
    err_text += "CDATA ブロックの開閉関係が不正です。\r\n";
    }
    // JSP コメント中
    else if (is_jsp_comment) {
    is_error = true;
    err_text += "JSP コメントの開閉関係が不正です。\r\n";
    }
    // JSP 中
    else if (is_jsp) {
    is_error = true;
    err_text += "JSP スクリプトレットの開閉関係が不正です。\r\n";
    }
    // スタックに終了タグあり
    else if (stack.length > 0) {
    is_error = true;
    err_text += "開始タグのない終了タグが見つかりました。\r\n";
    for (var i=0; i<stack.length; i++) {
    err_text += "<"+stack[i]+">\r\n";
    }
    }

    // エラーダイアログ表示
    if (is_error) {
    Shell.Popup(err_text, 0, "文法エラー", 0);
    return;
    }

    // 終了タグの挿入
    Editor.InsText(ins_text);

    // カーソルを動かさない場合は、元の位置に戻す
    if (!MOVE_CURSOR) {
    for (var i=0; i<ins_text.length; i++) {
    Editor.Left(0);
    }
    }
    })();
    • [547] 要手動修正 gis_dur 2012年02月04日 11:30

      UNICODE版サクラエディタをご利用の場合は修正不要です。
      ANSI版サクラエディタをご利用の場合は、以下の行を手動で修正する必要があります。

      22行目
      var UNICODE_VER = true;
      ↓
      var UNICODE_VER = false;

      49行目
      return (!c.match(/[ア-ンァィゥェォッャュョ゛゜ー、。「」・]/) && escape(c).length >= 4);
      ↓
      ア ン ァ ィ ゥ (中略) 「 」 ・ までを半角カナにする
      ※サクラエディタで行全体を選択して、メニューから「変換」「全角カタカナ→半角カタカナ」を実行すると楽です。
    • [549] Re:直前の閉じていない HTML/XML タグを閉じる pst11841 2012年02月04日 16:22

      gis_durさん、待ってました!需要あります!

      早速設定してみました。使ってみたところ、
      --
      [Line 49] 文字セットの範囲が不正です。
      --
      というエラーが出てしまいます。

      サクラエディタのバージョンは2.0.3.0。
      49行目の修正はUNICODE版なので必要はないと思います。

      よろしくお願いします。

      ▼ gis_durさん
      > コツコツバージョンアップし続けていたものをリリースします。
      > 今も需要あるかなあ?
      >
      > /**********************************************************
      > ** Close Last Tag 3.0 **
      > ***********************************************************
      > ** A "Sakura-Editor Macro" using WSH 5.6 **
      > ** For sakura.exe ver.1.6.2.0 and over **
      > ** zlib/libpng ライセンス **
      > ** Copyright (C) 2004-2012 gis_dur **
      > ***********************************************************
      > **【動作】 **
      > ** カーソル位置より前にある HTML/XML タグを **
      > ** ファイル先頭に向かって検索し、 **
      > ** 1. 終了タグのない開始タグ **
      > ** 2. 閉じていないHTMLコメント <!-- --> **
      > ** 3. 閉じていないCDATAブロック <![CDATA[ ]]> **
      > ** 4. 閉じていないJSPスクリプトレット <% %> **
      > ** 5. 閉じていないJSPコメント <%-- --%> **
      > ** がある場合、対応する終了タグを挿入します。 **
      > ** コメントタグ内は無視します。 **
      > **********************************************************/
      >
      > // サクラエディタ unicode 版の場合は true にする
      > var UNICODE_VER = true;
      > // xml モード(大文字・小文字を区別する)
      > var XML_MODE = false;
      > // 挿入した閉じタグの後ろにカーソルを移動するかどうか
      > var MOVE_CURSOR = true;
      > // 閉じタグを省略可能な要素名
      > var NO_CLOSE_TAG = "," +
      > [
      > "area", "base", "basefont", "bgsound", "br",
      > "col", "embed", "frame", "hr", "img",
      > "input", "isindex", "keygen", "link", "meta",
      > "nextid", "param", "spacer", "wbr"
      > ].join(",") + ",";
      >
      > /*********************************************************/
      >
      > // シェル
      > if (typeof(Shell) == "undefined") {
      > Shell = new ActiveXObject("WScript.Shell");
      > }
      >
      > // 文字列拡張
      > if (typeof(String.prototype.is_wide) == "undefined") {
      > String.prototype.is_wide = function() {
      > if (UNICODE_VER) return false;
      > if (this.length == 0) return false;
      > var c = (this.length == 1) ? this : this.charAt(0);
      > return (!c.match(/[ア-ンァィゥェォッャュョ゛゜ー、。「」・]/) && escape(c).length >= 4);
      > };
      > }
      >
      > (function() {
      > if (!XML_MODE) {
      > NO_CLOSE_TAG = NO_CLOSE_TAG.toUpperCase();
      > }
      > // タグを表す正規表現
      > var TAG_CHARS = "s!\"#$%&\'()=~|^\\`{+*}<>?@[;],/";
      > (function(){
      > var tmp = "";
      > for (var i=0; i<TAG_CHARS.length; i++) {
      > tmp += "\\"+TAG_CHARS.charAt(i);
      > }
      > TAG_CHARS = "[^"+tmp+"]+";
      > })();
      > var TAGS_EXPRESSION = new RegExp();
      > TAGS_EXPRESSION.compile("<!--|-->|<!\\[CDATA\\[|\\]\\]>|<%--|--%>|<%|%>|<"+TAG_CHARS+"([^>]*/>)?|<\\/"+TAG_CHARS+"", "g");
      >
      > // データ
      > var stack = new Array();
      > var ins_text = "";
      > var err_text = "";
      >
      > // ステート
      > var is_comment = false;
      > var is_cdata = false;
      > var is_jsp_comment = false;
      > var is_jsp = false;
      > var is_error = false;
      >
      > // テキストをすべて取得
      > Editor.CancelMode(0);
      > var cursorX = Number(Editor.ExpandParameter('$x')) - 1;
      > var cursorY = Number(Editor.ExpandParameter('$y')) - 1;
      > Editor.SelectAll(0);
      > var all_text = Editor.GetSelectedString(0);
      > Editor.CancelMode(0);
      >
      > // 改行を統一
      > all_text = all_text.replace(/\r\n|\r|\n/g, "\n");
      > var all_lines = all_text.split("\n");
      > var num_lines = all_lines.length;
      >
      > // カーソル以前のテキストをすべて取得
      > var tmp_text = all_lines[cursorY];
      > if (tmp_text == null) {
      > tmp_text = "";
      > }
      > if (num_lines-(cursorY+1) > 0) {
      > all_lines.splice(cursorY+1, num_lines-(cursorY+1));
      > }
      > for (var i=0; i<cursorX; i++) {
      > if (tmp_text.charAt(i).is_wide()) {
      > cursorX--;
      > }
      > }
      > all_lines[cursorY] = tmp_text.substring(0, cursorX);
      >
      > // タグを取得
      > var all_tags = all_lines.join(" ").match(TAGS_EXPRESSION);
      > var num_tags = (all_tags == null)? 0: all_tags.length;
      >
      > // 直前の開始タグを検索
      > for (var i=num_tags-1; i>=0; i--) {
      > // タグ文字列取得
      > var now_text = all_tags[i];
      > if (!XML_MODE) {
      > now_text = now_text.toUpperCase();
      > }
      >
      > // 特殊なステートにある場合
      > if (is_comment) {
      > if (now_text == "<!--") {
      > is_comment = false;
      > }
      > continue;
      > }
      > else if (is_cdata) {
      > if (now_text == "<![CDATA[") {
      > is_cdata = false;
      > }
      > continue;
      > }
      > else if (is_jsp_comment) {
      > if (now_text == "<%--") {
      > is_jsp_comment = false;
      > }
      > continue;
      > }
      > else if (is_jsp) {
      > if (now_text == "<%") {
      > is_jsp = false;
      > }
      > continue;
      > }
      >
      > // 特殊なステートに遷移する場合
      > if (now_text == "-->") {
      > is_comment = true;
      > continue;
      > }
      > else if (now_text == "<!--") {
      > ins_text = "-->";
      > break;
      > }
      > else if (now_text == "]]>") {
      > is_cdata = true;
      > continue;
      > }
      > else if (now_text == "<![CDATA[") {
      > ins_text = "]]>";
      > break;
      > }
      > else if (now_text == "--%>") {
      > is_jsp_comment = true;
      > continue;
      > }
      > else if (now_text == "<%--") {
      > ins_text = "--%>";
      > break;
      > }
      > else if (now_text == "%>") {
      > is_jsp = true;
      > continue;
      > }
      > else if (now_text == "<%") {
      > ins_text = "%>";
      > break;
      > }
      > // 閉じタグ不要
      > else if (now_text.indexOf("/>") != -1) {
      > continue;
      > }
      > // 閉じタグのスタックに追加
      > else if (now_text.indexOf("</") == 0) {
      > now_text = now_text.substring(2);
      > stack.push(now_text);
      > continue;
      > }
      >
      > // 要素名取得
      > now_text = now_text.substring(1);
      >
      > // 省略可能なタグの場合
      > if (NO_CLOSE_TAG.indexOf(","+now_text+",") != -1) {
      > if (stack.length == 0) {
      > continue;
      > }
      > else {
      > tmp_text = stack.pop();
      > if (now_text != tmp_text) {
      > stack.push(tmp_text);
      > }
      > continue;
      > }
      > }
      > // 通常のタグの場合
      > else {
      > if (stack.length == 0) {
      > ins_text = "</" + all_tags[i].substring(1) + ">";
      > break;
      > }
      > else {
      > tmp_text = stack.pop();
      > if (now_text != tmp_text) {
      > is_error = true;
      > err_text += "タグの包含関係が不正です。\r\n";
      > err_text += "<"+now_text+"> ... ... </"+tmp_text+">\r\n";
      > stack = new Array();
      > break;
      > }
      > }
      > }
      > }
      >
      > // コメント中
      > if (is_comment) {
      > is_error = true;
      > err_text += "コメントの開閉関係が不正です。\r\n";
      > }
      > // CDATA 中
      > else if (is_cdata) {
      > is_error = true;
      > err_text += "CDATA ブロックの開閉関係が不正です。\r\n";
      > }
      > // JSP コメント中
      > else if (is_jsp_comment) {
      > is_error = true;
      > err_text += "JSP コメントの開閉関係が不正です。\r\n";
      > }
      > // JSP 中
      > else if (is_jsp) {
      > is_error = true;
      > err_text += "JSP スクリプトレットの開閉関係が不正です。\r\n";
      > }
      > // スタックに終了タグあり
      > else if (stack.length > 0) {
      > is_error = true;
      > err_text += "開始タグのない終了タグが見つかりました。\r\n";
      > for (var i=0; i<stack.length; i++) {
      > err_text += "<"+stack[i]+">\r\n";
      > }
      > }
      >
      > // エラーダイアログ表示
      > if (is_error) {
      > Shell.Popup(err_text, 0, "文法エラー", 0);
      > return;
      > }
      >
      > // 終了タグの挿入
      > Editor.InsText(ins_text);
      >
      > // カーソルを動かさない場合は、元の位置に戻す
      > if (!MOVE_CURSOR) {
      > for (var i=0; i<ins_text.length; i++) {
      > Editor.Left(0);
      > }
      > }
      > })();
      • [550] Re2:直前の閉じていない HTML/XML タグを閉じる gis_dur 2012年03月18日 12:56

        返事が遅くなってすみません。

        確認したところ、マクロファイルを UTF-8 で保存すると同じ現象が起きました。
        SJIS で保存すると解消しませんか。


        ▼ pst11841さん
        > gis_durさん、待ってました!需要あります!
        >
        > 早速設定してみました。使ってみたところ、
        > --
        > [Line 49] 文字セットの範囲が不正です。
        > --
        > というエラーが出てしまいます。
        >
        > サクラエディタのバージョンは2.0.3.0。
        > 49行目の修正はUNICODE版なので必要はないと思います。
        >
        > よろしくお願いします。
        • [551] Re3:直前の閉じていない HTML/XML タグを閉じる pst11841 2012年03月18日 20:08

          pst11841 です。ご対応ありがとうございます。
          Shift-JISで保存しなおして、使えるようになりました。
          これで行きます
          ありがとうございました!