テキスト変換
概要
開いているドキュメントのテキストを変換します.
特徴
- 機能追加が簡単.
更新履歴
- 2013/1/23 初版
- 2013/1/24 グルーピング対応.replaceS, replaceL 対応.
使用方法
- 基本コードを拡張子 .js で保存します.
- 必要な拡張コードを追加します.
- 「拡張機能の追加」とある場所に,コードをコピペすれば拡張が可能です.
- 上から順にポップアップに表示されます.
- マクロを実行すると登録されている機能の一覧が表示されるので,選択して実行します.
- テキストを選択している場合は,対象を「選択テキスト」「全体」から選べます.
- テキストを選択していない場合は「全体」が対象です.
便利な使い方
- セパレータの挿入
f[f.length] = "--";
でセパレータを挿入できます(- の数は任意). - グルーピング
下のコードのようにコード拡張と似た書式で,グルーピングができます.
f[f.length] = {
title:"文字変更" // <= グルーピング名
group:function(f){ // <= グルーピング開始(お決まり文句)
f[f.length] = { // <= 以降はグルーピングされる機能を追加
title:"大文字に変換",
replace:function(text){ return text.toUpperCase() }
};
f[f.length] = {
title:"小文字に変換",
replace:function(text){ return text.toLowerCase() }
};
} // <= グルーピングの終了
};
コード
基本コード
#title = "テキスト変換"
// -----------------------------------------------------------------------------
// 手軽にテキスト変換を行うためのマクロ
// -----------------------------------------------------------------------------
var f = [];
// 拡張機能の追加
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
f[f.length] = {
title:"行頭の空白文字を削除",
replace:function(text){ return text.replace(/^[ \t ]+/mg, "") }
};
f[f.length] = {
title:"行末の空白文字を削除",
replace:function(text){ return text.replace(/[ \t ]+$/mg, "") }
};
f[f.length] = {
title:"行頭・行末の空白文字を削除",
replace:function(text){ return text.replace(/^[ \t ]+|[ \t ]+$/mg, "") }
};
f[f.length] = {
title:"空白行を削除",
replace:function(text){ return text.replace(/^\n/mg, "") }
};
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
// 基本機能
(function(){
var topMenu = CreatePopupMenu();
var menus = null;
var selMenu = null;
var docMenu = topMenu;
var DIFF_ID = 0x10000; // 適用対象を判別するための ID の最低値
var SELECTION_ID = 0x10000; // Selection を対象
var DOCUMENT_ID = 0x20000; // Document を対象
var EDITOR_ID = 0x40000; // Editor を対象(未対応)
// サブメニュー登録
var AddSubMenu = function(menu, text) {
var subMenu = null;
if (menu){
subMenu = CreatePopupMenu();
menu.AddPopup(text, subMenu);
}
return subMenu;
};
// コマンド登録
var commands = {}, id = 0;
var AddCommand = function(menus, text, cmd, flag) {
for (var i=0; i<menus.length; i++) {
if (menus[i]) {
menus[i].Add(text, (DIFF_ID << i) + id, flag);
commands[id] = cmd;
id++;
}
}
};
// 選択領域を行全体に変更してその文字列を返す
SelectLine = function(selection, isPosView) {
var posFlag = isPosView ? mePosView : mePosLogical;
var ty = selection.GetTopPointY(posFlag);
selection.SetActivePoint(posFlag, 1, selection.GetBottomPointY(posFlag));
selection.EndOfLine(false, posFlag);
selection.SetAnchorPoint(posFlag, 1, ty);
return selection.Text;
};
// 行単位処理
EnumLine = function(selection, isPosView, replace) {
var lines = SelectLine(selection, isPosView).split("\n");
var result = [];
for (var i=0; i<lines.length; i++) {
var text = replace(lines[i]);
if (text != null) {
result.push(text);
}
}
return result.join("\n");
}
// 選択文字列があるときは選択肢追加
var sel = document.Selection;
if (sel.Text) {
selMenu = AddSubMenu(topMenu, "選択文字列");
docMenu = AddSubMenu(topMenu, "全体");
}
// 選択肢追加
// 定義リストからメニューを作成
var ListToMenu = function(menus, f) {
for (var i=0; i<f.length; i++) {
if (typeof f[i]["title"] == "string") {
// グループ登録またはコマンド登録
if (typeof f[i]["group"] == "function") {
var group = [];
f[i].group(group);
var subMenus = [];
for (var j=0; j<menus.length; j++) {
subMenus.push(AddSubMenu(menus[j], f[i].title));
}
ListToMenu(subMenus, group);
} else if (typeof f[i]["replace"] == "function") {
// 通常コマンド
var exec = function(replace, text, isViewMode, selection){ return replace(text, selection) };
AddCommand(menus, f[i].title, {replace:f[i].replace, exec:exec});
} else if (typeof f[i]["replaceS"] == "function") {
// 行全体選択
var exec = function(replace, text, isViewMode, selection){ return replace(SelectLine(selection, isViewMode), selection) };
AddCommand(menus, f[i].title, {replace:f[i].replaceS, isViewMode:f[i]["view"], exec:exec});
} else if (typeof f[i]["replaceL"] == "function") {
// 行単位処理
var exec = function(replace, text, isViewMode, selection){ return EnumLine(selection, isViewMode, replace) };
AddCommand(menus, f[i].title, {replace:f[i].replaceL, isViewMode:f[i]["view"], exec:exec});
}
} else if (typeof f[i] == "string" && /^-+$/.test(f[i])) {
// セパレータ処理
AddCommand(menus, "", null, meMenuSeparator);
}
}
};
ListToMenu([selMenu, docMenu], f);
// ポップアップを表示して選択されたコマンドを実行
var mePosCaret = 0;
var select = topMenu.Track(mePosMouse);
if (select > 0) {
var command = commands[select&(DIFF_ID-1)];
if (select & SELECTION_ID) {
sel.Text = command.exec(command.replace, sel.Text, command["isViewMode"], sel);
} else if (select & DOCUMENT_ID) {
sel.SelectAll();
Document.Text = command.exec(command.replace, Document.Text, command["isViewMode"], sel);
}
}
})();
拡張コード
ご自由に追加してください!
空白削除
f[f.length] = {
title:"空白削除",
group:function(f){
f[f.length] = {
title:"行頭の空白文字を削除",
replace:function(text){ return text.replace(/^[ \t ]+/mg, "") }
};
f[f.length] = {
title:"行末の空白文字を削除",
replace:function(text){ return text.replace(/[ \t ]+$/mg, "") }
};
f[f.length] = {
title:"行頭・行末の空白文字を削除",
replace:function(text){ return text.replace(/^[ \t ]+|[ \t ]+$/mg, "") }
};
f[f.length] = {
title:"空白行を削除",
replaceL:function(text){ return text=="" ? null : text }
};
f[f.length] = {
title:"カンマ前後の空白文字を削除",
replace:function(text){ return text.replace(/^[ \t ]+|[ \t ]+$/mg, "").replace(/[ \t ]*,[ \t ]*/mg, ","); }
};
}
};
文字変換
f[f.length] = {
title:"文字変換",
group:function(f){
f[f.length] = {
title:"大文字に変換",
replace:function(text){ return text.toUpperCase() }
};
f[f.length] = {
title:"小文字に変換",
replace:function(text){ return text.toLowerCase() }
};
f[f.length] = {
title:"全角⇒半角",
group:function(f){
f[f.length] = {
title:"英字",
replace:function(text){ return text.replace(/[A-Za-z]/mg, function(s){ return String.fromCharCode(s.charCodeAt(0) - 0xFEE0) }) }
};
f[f.length] = {
title:"数字",
replace:function(text){ return text.replace(/[0-9]/mg, function(s){ return String.fromCharCode(s.charCodeAt(0) - 0xFEE0) }) }
};
f[f.length] = {
title:"英数字",
replace:function(text){ return text.replace(/[A-Za-z0-9]/mg, function(s){ return String.fromCharCode(s.charCodeAt(0) - 0xFEE0) }) }
};
}
};
f[f.length] = {
title:"半角⇒全角",
group:function(f){
f[f.length] = {
title:"英字",
replace:function(text){ return text.replace(/[A-Za-z]/mg, function(s){ return String.fromCharCode(s.charCodeAt(0) + 0xFEE0) }) }
};
f[f.length] = {
title:"数字",
replace:function(text){ return text.replace(/[0-9]/mg, function(s){ return String.fromCharCode(s.charCodeAt(0) + 0xFEE0) }) }
};
f[f.length] = {
title:"英数字",
replace:function(text){ return text.replace(/[A-Za-z0-9]/mg, function(s){ return String.fromCharCode(s.charCodeAt(0) + 0xFEE0) }) }
};
}
};
}
};
ソート
f[f.length] = {
title:"ソート",
group:function(f){
f[f.length] = {
title:"昇順ソート(文字列)",
replaceS:function(text){ return text.split("\n").sort().join("\n") }
};
f[f.length] = {
title:"降順ソート(文字列)",
replaceS:function(text){ return text.split("\n").sort(function(a, b){ return ((a < b) ? 1 : ((a > b) ? -1 : 0)) }).join("\n") }
};
}
};
重複行排除
「連続する重複行を削除」の移植を含みます.
f[f.length] = {
title:"重複削除",
group:function(f){
f[f.length] = {
title:"連続する重複を削除",
replaceS:function(text){
text = text.split("\n");
var result = [text[0]];
for (var i=1; i<text.length; i++) {
if (text[i] !== text[i-1]) {
result.push(text[i]);
}
}
return result.join("\n");
}
};
f[f.length] = {
title:"重複行を削除",
replaceS:function(text){
text = text.split("\n");
var result = [], map = {};
for (var i=0; i<text.length; i++) {
if (!map[text[i]]) {
map[text[i]] = true;
result.push(text[i]);
}
}
return result.join("\n");
}
};
}
};
文字列追加
f[f.length] = {
title:"文字列追加",
group:function(f){
f[f.length] = {
title:"先頭",
replaceL:(function(text){
var add = null;
return function(text){
if (!add) {
add = Prompt("追加する文字列を入力してください.", "");
if (!add) { Quit(); }
}
return add + text;
};
})()
};
f[f.length] = {
title:"末尾",
replaceL:(function(text){
var add = null;
return function(text){
if (!add) {
add = Prompt("追加する文字列を入力してください.", "");
if (!add) { Quit(); }
}
return text + add;
};
})()
};
}
};
BASE64エンコード(Unicode)
f[f.length] = {
title:"BASE64エンコード(Unicode)",
replace:function(text){
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
var Ch = function(n){ return n<text.length ? text.charCodeAt(n) : 0 };
var len = text.length, pad = len % 3, s = "";
for (var i=0; i<len; i+=3) {
var tmp = (Ch(i)<<16) | (Ch(i+1)<<8) | Ch(i+2);
s += map[(tmp>>>18)&0x3F] + map[(tmp>>>12)&0x3F] + map[(tmp>>>6)&0x3F] + map[tmp&0x3F];
}
if (pad) { s = s.substring(0, s.length-(3-pad)) + "===".substring(pad) }
return s;
}
};
開発者向け資料
これは拡張コードを開発される方向けの仕様です.
拡張コードは次のいずれかの関数を実装します.
- replace
- replaceS
- replaceL
replace
function replace(
text : string,
selection : Selection
) : string
最も基本的な変換関数です.
選択されている文字列,またはドキュメント全体の文字列を引数として,
変換結果を返します.
selection 引数は通常必要有りません.
Selection の持つ関数を利用したい場合などに利用します.
replaceS
function replaceS(
text : string,
selection : Selection
) : string
行途中の選択がされている場合に,行全体を選択し直してから実行される変換関数です.
行は論理行で処理しますが,下記のように view:true を定義時に登録することで,
表示行で処理することもできます.
f[f.length] = {
title:"replaceL",
view:true,
replaceS:function(text){ return text }
};
replaceL
function replaceL(
text : string,
selection : Selection
) : string
行単位で処理する場合に利用する変換関数です.
渡される text は,他の関数と違い「1 行分の文字列」です.
String.replace や String.split("\n").join("\n") を利用することで同様の処理が行えますが,より簡易的に処理するために用意されています.
次の 2 つの定義は同じ処理(空白行削除)をします.
replaceS:function(text){ return text.replace(/^\n/mg, "") }
replaceL:function(text){ if (text != "") { return text } }
replaceL 関数の場合,null を返すかあるいは return しない場合に行を削除します.
replaceL 関数は行毎に呼ばれるため,全体で 1 回のみの処理を記述するのが面倒です.
もし必要な場合は,拡張コードの「文字列追加」のようにクロージャを利用する必要があります.
ご意見・ご要望
何かありましたら,右の [編集] から追記してください.対応するもかしれません.
スポンサーリンク