// // HTML タグ削除マクロ DeleteTag.mac Version 4.07 (2003/04/12) // // Made by IKKI http://www18.big.or.jp/~fujiwara/ikki/ // //------ 設定 ---------------------------------------------------------------- // ▼ 終了タグが省略可能な要素(dt dd li p option td th tr colgroup tbody thead tfoot head body html)について // (1) 終了タグなし: $MustOmitted = ""; // (2) 終了タグ省略可: $MightOmitted = "dt dd li p option td th tr colgroup tbody thead tfoot head body html"; // 説明はドキュメントに書いてあります。わからないときは全部 (2) に入れておいてください。 // ▼ タグ外で実行したらどうするか // 0:何もしない // 2:最初に見つけたタグを削除(確認あり) // 3:最初に見つけたタグを削除(確認なし) // 4:カーソル位置の要素を削除(確認あり) // 5:カーソル位置の要素を削除(確認なし) // 9:任意のコマンドを実行(85行目付近で指定) #WhereOutside = 4; // ▼ 範囲選択してたらどうするか // 1:範囲内に含まれるタグをすべて削除(確認あり) // 2:範囲内に含まれるタグをすべて削除(確認なし) #WhereSelecting = 1; //------ 設定ここまで -------------------------------------------------------- $MustOmitted = " br img hr col input area param basefont base meta link isindex frame " + $MustOmitted + " "; $MightOmitted = " " + $MightOmitted + " "; $Delimiter = "[ \\t\\x0a/>]"; $AnyTag = " #tpl || (#stl == #tpl && #stc > #tpc)) { // <→ > 影響範囲 if (#stl < #tdl || (#stl == #tdl && #stc < #tdc)) #stc = #tpc; // < ←> タグ内 else if (#stl == #tdl) #stc = #stc - #tdc + #tpc; // < >→ タグ外 } // 行補正 if (#stl > #tpl) { // <↓ > 影響範囲 if (#stl < #tdl) #stl = #tpl; // < ↑> タグ内 else #stl = #stl - #tdl + #tpl; // < >↓ タグ外 } return; SelectTag: // タグを選択 // 準備: タグの先頭(「<」の直前)にカーソルを置く // 効果: #tpc, #tpl, #tdc, #tdl = 選択範囲 (column, lineno) if (code != '<') call Error 9; #tpc = column; #tpl = lineno; searchdown ">"; if (!result) call Error 3; right; #tdc = column; #tdl = lineno; beginsel; movetolineno #tpc + 1, #tpl; endsel; return; SeekPairDown: // 対応する終了タグを探す #searchhere = yes; // 初回はカーソル位置から検索開始(DeleteTag.mac 専用) while (true) { if (#type & 0x10) { // 終了タグのとき while ($name != $names[#d]) { // 食い違ったらスタック巻き戻し if (#debug) call Confirm "違う"; #d = #d - 1; if (#d < 1) return false; // 見つからなかったらそこまで } #d = #d - 1; // 外へ if (#d < 1) return true; if (#debug) call Confirm "外へ"; } else if (#type & 0x03) { // 開始タグのとき #d = #d + 1; // 中へ $names[#d] = $name; // スタックに積む if (#type & 0x02) { // 終了タグあり call IgnoreCase $name; $seeks[#d] = $$return; } else { $seeks[#d] = ""; } if (#debug) call Confirm "中へ"; } call GetNextTag 1; // 次を検索(下方向) } call Error 9; SeekPairUp: // 対応する開始タグを探す while (true) { if (#type & 0x10) { // 終了タグのとき #d = #d + 1; // 中へ $names[#d] = $name; // スタックに積む if (#type & 0x02) { // 終了タグあり call IgnoreCase $name; $seeks[#d] = $$return; } else { // 終了タグ省略可/終了タグなし(設定ミスを考慮) $seeks[#d] = ""; } if (#debug) call Confirm "中へ"; } else if (#type & 0x03) { // 開始タグのとき if ($name != $names[#d]) { if (#type & 0x02) call Error 2; // else 無視して次へ } else { #d = #d - 1; // 外へ if (#d < 1) return true; // 抜ける if (#debug) call Confirm "外へ"; } } call GetNextTag 0; // 次を検索(上方向) } call Error 9; IgnoreCase: // 大文字小文字を区別しない正規表現を生成 // 引数: $$1 = 小文字 // 返り値: $$return = 正規表現 ##i = strlen($$1); while (##i) { // およそ 0.44ms/char ##c = ascii(rightstr($$1, ##i)); if (##c < 'a' || ##c > 'z') $$r = $$r + char(##c); // メタキャラクタは考慮してない else $$r = $$r + "[" + char(##c) + char(##c - 32) + "]"; ##i = ##i - 1; } return $$r; GetNextTag: // 次のタグを検索・取得 // 準備: #seeks[#d] = 検索語(正規表現) "":不特定のタグ // 引数: ##1 = 0: 上方向 != 0: 下方向 // 効果: #type = ビットフラグ // ___x ____ = 1:終了タグ 0:開始タグ // ____ __xx = 00:終了タグなし 01:終了タグ省略可 10:終了タグあり // $name = 要素名(小文字) if ($seeks[#d] == "") setsearch $AnyTag, 0x10; else setsearch "= 'A' && code <= 'Z') $name = $name + char(code + 32); // 小文字化 else if (code <= ' ' || code == '/' || code == '>') break; // 区切り文字 else $name = $name + char(code); // そのまま right; } if (strstr($MustOmitted, " " + $name + " ") >= 0) #type = #type & 0xfc; // 終了タグなし else if (strstr($MightOmitted, " " + $name + " ") >= 0) #type = #type & 0xfc | 0x01; // 終了タグ省略可 else #type = #type & 0xfc | 0x02; // 終了タグあり } if (#debug) message "$name = '" + $name + "'\n#type = " + hex(#type); moveto ##tpx, ##tpy; #c = #c + 1; if (#c == 20) title "探索中..."; return; Selecting: // 範囲選択してる場合 if (#WhereSelecting == 1) { question "範囲内に含まれるすべてのタグを削除します。\nよろしいですか?"; if (!result) call Error 0; } #spx = seltopx; #spy = seltopy; #sdx = selendx; #sdy = selendy; escape; moveto #spx, #spy; #spl = lineno; #spc = column; moveto #sdx, #sdy; if (column == 0) { up; golineend2; } #sdl = lineno; #sdc = column; while (true) { searchup $AnyTag, regular; if (!result) break; #tpl = lineno; #tpc = column; if (lineno < #spl || (lineno == #spl && column < #spc)) break; // タグ先頭が選択範囲外 searchdown ">"; if (!result) call Error 3; right; if (lineno > #sdl || (lineno == #sdl && column > #sdc)) { movetolineno #tpc + 1, #tpl; continue; } // タグ末尾が選択範囲外 beginsel; movetolineno #tpc + 1, #tpl; if (#debug) { question "削除?"; if (!result) endmacro; } delete; } moveto #spx, #spy; return; RectSelecting: // BOX 選択してる場合 if (#WhereSelecting == 1) { question "BOX 範囲内に含まれるすべてのタグを削除します。\nよろしいですか?"; if (!result) call Error 0; } #spx = seltopx; #spy = seltopy; #sdx = selendx; #sdy = selendy; escape; moveto #sdx, #sdy; while (true) { searchup $AnyTag, regular; if (!result) break; #tpx = x; #tpy = y; if (y < #spy || (y == #spy && x < #spx)) break; // タグ先頭が選択範囲外 if (x < #spx || x >= #sdx) continue; // searchdown ">"; if (!result) call Error 3; right; if (y > #sdy || (y <= #sdy && x > #sdx)) { moveto #tpx, #tpy; continue; } // タグ末尾が選択範囲外 // タグが複数行の場合 if (y > #tpy) { #tdx = x; #tdy = y; ##covered = true; while (y > #tpy) { golinetop; if (x < #spx) { ##covered = false; break; } // タグ内の行頭が選択範囲外 up; golineend; if (x > #sdx) { ##covered = false; break; } // タグ内の行末が選択範囲外 } if (!##covered) { moveto #tpx, #tpy; continue; } moveto #tdx, #tdy; } beginsel; moveto #tpx, #tpy; if (#debug) { question "削除?"; if (!result) endmacro; } delete; } moveto #spx, #spy; return; Initialize: // 初期化 #starttime = tickcount; #orgc = column; #orgl = lineno; $searchbuffer = searchbuffer; #searchoption = searchoption; if (!#debug) disabledraw; return; Finalize: // 後始末 setsearch $searchbuffer, #searchoption; enabledraw; return; Error: // エラー処理 // 引数: ##1 = エラー番号 // 0: キャンセルした // 1: タグが見つからない // 2: ネスト外へ出た // 3: 「>」が見つからない // 9: while(true) を抜けた enabledraw; if (##1 == 0) { escape; movetolineno #stc + 1, #stl; } else if (##1 == 1) { message "対応するタグが見つかりません\n" + str(tickcount - #starttime) + "ms / " + str(#c) + "tags"; } else if (##1 == 2) { question str(lineno) + ": <" + leftstr("/", #type & 0x10) + $name + "> の終了タグが見あたりません\n無視して続けますか?"; if (result) { if (!#debug) disabledraw; return; } } else if (##1 == 3) { message "「>」が見つかりません"; } else if (##1 == 9) { message "マクロが予想外の動作をしました"; } movetolineno #orgc + 1, #orgl; call Finalize; endmacro; Confirm: // 動作確認(デバッグ用) ##p = 1; while (##p <= #d) { // スタックトレース $$stuck = $$stuck + "\n" + str(##p) + ": " + $names[##p] + "\t" + $seeks[##p]; ##p = ##p + 1; } question "<" + leftstr("/", #type & 0x10) + $name + ">\t" + $$1 + "\n" + $$stuck; if (!result) endmacro; return; // (C) IKKI 2002