マクロ「テキスト整形」の仕様変更について (2015/02/14)
モード R/RS 実行後、処理した範囲を選択し直すように
旧仕様では、コマンド実行後は範囲選択が 解 除 されました。↵
新仕様では、コマンド実行前に選択範囲を 記 憶 し、実行後に 復 元 します。↵
処理の結果、字数が 増 減 した場合は、選択範囲が 調 整 されます。↵
- ↓ コマンド「空白文字を除去」実行
旧仕様では、コマンド実行後は範囲選択が解除されました。↵
新仕様では、コマンド実行前に選択範囲を記憶し、実行後に復元します。↵
処理の結果、字数が増減した場合は、選択範囲が調整されます。↵
この変更により、コマンドの効果範囲が目視できるようになり、また、選択し直す手間なく別の処理に移ることができるようになります。
- モード R では、選択範囲の始点終点の位置関係が維持されます。
- モード RS では、選択範囲を行頭行末まで拡張した状態が記憶されます。始点は上端行頭、終点は下端行末となります。
- コマンド実行中にカーソル位置を移動させる処理がある場合には対応できません。
モード RM の廃止
モード RM (一行ごとに処理) は、マクロ「テキスト変換」の関数タイプ replaceL に相当し、モード RS で実現可能な処理をより簡素に記述するために設けられた機能です。
しかし、以下のような難点が見受けられることから、廃止を考えるに至りました。
- モード RS より簡素に記述できるとは必ずしも限らない。
- モード RS で実現可能=代替可能であり、RM ならではの利点が無い。
- モード R/RS に比べ処理が異質で、コマンドを作る際はそれを考慮しなければならない。
※異質=R/RS が「選択範囲の文字列」を対象に処理を行うのに対し、RM は「選択範囲の各行の文字列」を対象に処理を行う。
//※モード RM では「クロージャ」という仕組みを使用する必要があり難解
f.push(["各行行頭に文字列付加...","RM",(function(a){
var p=null; return function(a){ if(!p){ if(!(p=Prompt("各行行頭に付加する文字列:",""))){Quit()} } return p+a } })()]);
//※モード RS で replace(正規表現) を使用するほうが簡素に記述できる
f.push(["各行行頭に文字列付加...","RS",function(a){
var p=Prompt("各行行頭に付加する文字列:",""); if(!p)Quit(); return a.replace(/^/gm,p) }]);
//※モード RM でも、
f.push(["空白行を削除","RM",function(a){
return a.match(/^[ \t]*$/)? null:a }]);
//※モード RS でも、必要な知識や字数がほぼ変わらない時がある
f.push(["空白行を削除","RS",function(a){
return a.replace(/^[ \t]*$\n?/gm,"") }]);
//※モード RM なら正規表現に頼らず簡素に記述できるコマンドもあるが、
f.push(["インデント(半角空白2個)","RM",function(a){
return " "+a }]);
f.push(["インデント(半角空白2個)","RS",function(a){
return a.replace(/^/gm," ") }]);
//※正規表現を利用したコマンドも数多くあり、利点になりづらい
f.push(["行頭 \/\/ を付加/削除","RM",function(a){
return a.match(/^\/\/.*$/)? a.slice(2): "\/\/"+a }]);
f.push(["行頭 \/\/ を付加/削除","RS",function(a){
return a.replace(/^(\/\/)?/gm,function(s){return s? "": "\/\/"}) }]);
モード CR の廃止、String.replaceBatch メソッドの追加
モード CR (連続置換) は、replace を連鎖させる記法(メソッドチェーン)をより簡素に記述するために設けられた機能です。
f.push(["コマンド名","R",function(a){
return a.replace(/ABC/g,"DEF").replace(/\(1\)/g,"①").replace(/GHI/gi,"JKL") }]);
//↓簡素化
f.push(["コマンド名","CR",function(a){
return [ ["ABC","DEF"],["(1)","①"],[/GHI/gi,"JKL"] ]}]);
しかし、モードの一種としたがゆえに、他のモードでは利用できない事、replace のような使い方ができない事が難点としてありました。
replaceBatch メソッドは、この難点を解消するために設けられる機能です。
//※モード R で利用する(基本形)
f.push(["コマンド名","R",function(a){
return a.replaceBatch([ ["ABC","DEF"],["(1)","①"],[/GHI/gi,"JKL"] ]) }]);
//※モード RS で利用する(選択範囲を拡張)
f.push(["コマンド名","RS",function(a){
return a.replaceBatch([ ["ABC","DEF"],["(1)","①"],[/GHI/gi,"JKL"] ]) }]);
//※モード F で利用する(▲非推奨)
f.push(["コマンド名","F",function(a){
a.Text = a.Text.replaceBatch([ ["ABC","DEF"],["(1)","①"],[/GHI/gi,"JKL"] ]) }]);
//※replace のようにメソッドチェーンが可能
f.push(["コマンド名","R",function(a){
return a.replace(省略).replaceBatch([ 省略 ]).replace(省略) }]);
モード CR ⇒ R (replaceBatch) への移行方法
基本的にモード CR を継承した機能であるため、手直しすることで移行が可能です。
f.push(["コマンド名","CR",function(a){
return [ [検索1,置換1],[検索2,置換2],[検索3,置換3]… ]}]);
- ↓
f.push(["コマンド名","R",function(a){
return a.replaceBatch([ [検索1,置換1],[検索2,置換2],[検索3,置換3]… ]) }]);
変更点まとめ
| 機能 | 旧仕様 | 新仕様 | 備考 |
|---|---|---|---|
| モード F | 利用可 | 利用可 | 変更なし |
| モード R | 利用可 | 利用可 | 選択範囲を維持・調整するように |
| モード RS | 利用可 | 利用可 | 選択範囲を維持・調整するように |
| モード RM | 利用可 | 廃止 | モード RS に作り替え |
| モード CR | 利用可 | 廃止 | replaceBatch メソッドに移行 |
| replaceBatch | エラー | 利用可 | ※旧仕様ではコマンド実行時にエラーが発生する |
基本コード(先行版)
※正式版では変更となる場合があります。ご了承ください。
//■テキスト整形
// 2013/09/15-2015/02/14 (先行版)
//■拡張コード:コマンド一覧
var f = [];
// ----------------- ↓ここより下に拡張コードを追加
// ----------------- ↑ここより上に拡張コードを追加
/*■拡張コード:書式
//▼コマンド
f.push(["コマンド名","モード",function(引数){マクロ}]);
//▽モード F (Function) - 関数を実行
function( Document.Selection ) : 戻値なし
//▽モード R (Replace) - 選択範囲を置換
//▽モード RS (Select-line) - 選択範囲を行頭行末まで拡張して置換
function( Document.Selection.Text ) : String
//▼サブメニュー
f.push(["メニュー名",function(f){コマンドなど}]);
//▼セパレータ
f.push(["----"]);
// ----------------- */
//■メソッド:連続置換
//String.replaceBatch([ [検索1,置換1],[検索2,置換2],[検索3,置換3]… ]);
String.prototype.replaceBatch = function(a) { //▲引数の型検査はしていない
var _this = this;
for (var i=0,n=a.length; i<n; i++) {
if (typeof a[i][0]==="string") //◆特殊文字をエスケープし、"g"フラグを付加
a[i][0] = new RegExp(a[i][0].replace(/([$()*+.?[\\\]^{|}])/g,"\\$1"),"g");
_this = _this.replace(a[i][0],a[i][1]);
}
return _this;
};
//■実行コード
(function(){
var sel = Document.Selection;
var cmd = [], cid = 1; //コマンド格納用,ID
//メニュー生成用関数
function ListToMenu(List, Menu) {
for (var i=0, n=List.length; i<n; i++) {
var $L = List[i], $Ln = List[i].length;
if (typeof $L[0]!=="string") continue;
switch (true) {
//◆コマンド $L = ["コマンド名","モード",function]
case ($Ln===3 && /^(F|RS?)$/.test($L[1]) && typeof $L[2]==="function"):
cmd[cid] = {"mode":$L[1], "func":$L[2]};
Menu.Add($L[0]+"\t"+$L[1], cid++);
break;
//◆サブメニュー $L = ["メニュー名",function]
case ($Ln===2 && typeof $L[1]==="function"):
var sub_f = [], sub_popup = CreatePopupMenu();
$L[1](sub_f);
Menu.AddPopup($L[0], sub_popup);
ListToMenu(sub_f, sub_popup); //再帰処理:サブメニュー作成
break;
//◆セパレータ $L = ["----"]
case ($Ln===1 && /^-+$/.test($L[0])):
Menu.Add("", 0, meMenuSeparator);
break;
}
}
};
//コマンド一覧からメニュー生成
var popup = CreatePopupMenu();
ListToMenu(f, popup);
//ポップアップメニューを表示して処理
if (cid = popup.Track(mePosMouse)) { //※キャンセル(Esc)時は0が返る
var $C = cmd[cid];
switch ($C["mode"]) {
case "F": //関数を実行
$C["func"](sel);
break;
case "RS": //選択範囲を行頭行末まで拡張
selectLine();
case "R": //選択範囲を置換
var pos = new Pos(); //選択範囲の記憶
sel.Text = $C["func"](sel.Text);
pos.set(); //選択範囲の設定
break;
}
}
//■選択範囲を行頭行末まで拡張
function selectLine() {
var sel = Document.Selection;
var ty = sel.GetTopPointY(mePosLogical);
var by = sel.GetBottomPointY(mePosLogical);
var bx = sel.GetBottomPointX(mePosLogical);
var br =(sel.Text.match(/\n/g)||[]).length;
if (bx==1 && by-ty==br && br) by--; //次行行頭を含めないよう対策
sel.SetActivePoint(mePosLogical, 1, by);
sel.EndOfLine(false, mePosLogical);
sel.SetAnchorPoint(mePosLogical, 1, ty);
};
//■位置情報オブジェクト
function Pos() {
var sel = Document.Selection;
this.get = function() {
this.acp = sel.GetActivePos();
this.anp = sel.GetAnchorPos();
this.len = Document.Text.length;
};
this.set = function() { //字数変化を加味して範囲選択
var acp = this.acp, anp = this.anp, gap = Document.Text.length - this.len;
sel.SetActivePos((acp<anp)? acp: acp+gap);
sel.SetAnchorPos((acp<anp)? anp+gap: anp);
};
return this.get();
};
})();
拡張コード(先行版)
※正式版では変更となる場合があります。ご了承ください。
モード RM ⇒ RS
※上段=旧仕様/下段=新仕様
f.push(["行頭 \/\/ を付加/削除","RM",function(a){
return a.match(/^\/\/.*$/)? a.slice(2): "\/\/"+a }]);
f.push(["行頭 \/\/ を付加/削除","RS",function(a){
return a.replace(/^(\/\/)?/gm,function(s){return s? "": "\/\/"}) }]);
f.push(["インデント(半角空白2個)","RM",function(a){
return " "+a }]);
f.push(["インデント(半角空白2個)","RS",function(a){
return a.replace(/^/gm," ") }]);
f.push(["各行行頭に貼り付け","RM",function(a){
return ClipboardData.GetData().replace(/(\r?\n|\r)$/,"")+a }]);
f.push(["各行行末に貼り付け","RM",function(a){
return a+ClipboardData.GetData().replace(/(\r?\n|\r)$/,"") }]);
f.push(["各行行頭に貼り付け","RS",function(a){
var c=ClipboardData.GetData().replace(/(\r?\n|\r)$/,""); return a.replace(/^/gm,c) }]);
f.push(["各行行末に貼り付け","RS",function(a){
var c=ClipboardData.GetData().replace(/(\r?\n|\r)$/,""); return a.replace(/$/gm,c) }]);
f.push(["各行行頭に文字列付加...","RM",(function(a){
var c=null; return function(a){ if(!c){ if(!(c=Prompt("各行行頭に付加する文字列:",""))){Quit()} } return c+a } })()]);
f.push(["各行行末に文字列付加...","RM",(function(a){
var c=null; return function(a){ if(!c){ if(!(c=Prompt("各行行末に付加する文字列:",""))){Quit()} } return a+c } })()]);
f.push(["各行行頭に文字列付加...","RS",function(a){
var p=Prompt("各行行頭に付加する文字列:",""); if(!p)Quit(); return a.replace(/^/gm,p) }]);
f.push(["各行行末に文字列付加...","RS",function(a){
var p=Prompt("各行行末に付加する文字列:",""); if(!p)Quit(); return a.replace(/$/gm,p) }]);
f.push(["空白行を削除","RM",function(a){
return a.match(/^[ \t]*$/)? null:a }]);
f.push(["空白行を削除","RS",function(a){
return a.replace(/^[ \t]*$\n?/gm,"") }]);
f.push(["入力文字列を含む行を削除...","RM",(function(a){
var c=null; return function(a){ if(!c){ if(!(c=Prompt("以下の文字列を含む行を削除:",""))){Quit()} } return (a.indexOf(c)>=0)? null:a } })()]);
f.push(["入力文字列を含まない行を削除...","RM",(function(a){
var c=null; return function(a){ if(!c){ if(!(c=Prompt("以下の文字列を含まない行を削除:",""))){Quit()} } return (a.indexOf(c)>=0)? a:null } })()]);
f.push(["入力文字列を含む行を削除...","RS",function(a){
var p=Prompt("以下の文字列を含む行を削除:",""); if(!p)Quit(); return a.replace(/^(.*)$\n?/gm,function(s,t){return (t.indexOf(p)>=0)? "":s}) }]);
f.push(["入力文字列を含まない行を削除...","RS",function(a){
var p=Prompt("以下の文字列を含まない行を削除:",""); if(!p)Quit(); return a.replace(/^(.*)$\n?/gm,function(s,t){return (t.indexOf(p)>=0)? s:""}) }]);
f.push(["正規表現に一致する行を削除...","RM",(function(a){
var c=null; return function(a){ if(!c){ if(!(c=Prompt("以下の正規表現に一致する行を削除:",""))){Quit()}else{c=new RegExp(c)} } return c.test(a)? null:a } })()]);
f.push(["正規表現に一致しない行を削除...","RM",(function(a){
var c=null; return function(a){ if(!c){ if(!(c=Prompt("以下の正規表現に一致しない行を削除:",""))){Quit()}else{c=new RegExp(c)} } return c.test(a)? a:null } })()]);
f.push(["正規表現に一致する行を削除...","RS",function(a){
var p=Prompt("以下の正規表現に一致する行を削除:",""); if(!p)Quit(); p=new RegExp(p); return a.replace(/^(.*)$\n?/gm,function(s,t){return p.test(t)? "":s}) }]);
f.push(["正規表現に一致しない行を削除...","RS",function(a){
var p=Prompt("以下の正規表現に一致しない行を削除:",""); if(!p)Quit(); p=new RegExp(p); return a.replace(/^(.*)$\n?/gm,function(s,t){return p.test(t)? s:""}) }]);
モード CR ⇒ R (replaceBatch)
※新仕様のみ掲載
f.push(["連続する!?を整形","R",function(a){
return a.replaceBatch([ [/[!!][!!??]*[!!]/g,"!!"],[/[!!][!!??]*[??]/g,"!?"],[/[??][!!??]*[!!]/g,"?!"],[/[??][!!??]*[??]/g,"??"] ]) }]);
f.push(['実体参照 &&"<> → &&xxx;',"R",function(a){
return a.replaceBatch([ ["&","&"],['"',"""],["<","<"],[">",">"] ]) }]);
f.push(['実体参照 &&xxx; → \u2423><"&&',"R",function(a){
return a.replaceBatch([ [" "," "],[">",">"],["<","<"],[""",'"'],["&","&"] ]) }]);
f.push(['実体参照 &&"<>\u2423 → &&xxx;',"R",function(a){
return a.replaceBatch([ ["&","&"],['"',"""],["<","<"],[">",">"],[" "," "] ]) }]);
f.push(["半角カナ→全角","R",function(a){
return a.replaceBatch([ ["。","。"],["「","「"],["」","」"],["、","、"],["・","・"],["ヲ","ヲ"],["ァ","ァ"],["ィ","ィ"],["ゥ","ゥ"],["ェ","ェ"],["ォ","ォ"],["ャ","ャ"],["ュ","ュ"],["ョ","ョ"],["ッ","ッ"],["ー","ー"],["ア","ア"],["イ","イ"],["ヴ","ヴ"],["ウ","ウ"],["エ","エ"],["オ","オ"],["ガ","ガ"],["ギ","ギ"],["グ","グ"],["ゲ","ゲ"],["ゴ","ゴ"],["カ","カ"],["キ","キ"],["ク","ク"],["ケ","ケ"],["コ","コ"],["ザ","ザ"],["ジ","ジ"],["ズ","ズ"],["ゼ","ゼ"],["ゾ","ゾ"],["サ","サ"],["シ","シ"],["ス","ス"],["セ","セ"],["ソ","ソ"],["ダ","ダ"],["ヂ","ヂ"],["ヅ","ヅ"],["デ","デ"],["ド","ド"],["タ","タ"],["チ","チ"],["ツ","ツ"],["テ","テ"],["ト","ト"],["ナ","ナ"],["ニ","ニ"],["ヌ","ヌ"],["ネ","ネ"],["ノ","ノ"],["バ","バ"],["ビ","ビ"],["ブ","ブ"],["ベ","ベ"],["ボ","ボ"],["パ","パ"],["ピ","ピ"],["プ","プ"],["ペ","ペ"],["ポ","ポ"],["ハ","ハ"],["ヒ","ヒ"],["フ","フ"],["ヘ","ヘ"],["ホ","ホ"],["マ","マ"],["ミ","ミ"],["ム","ム"],["メ","メ"],["モ","モ"],["ヤ","ヤ"],["ユ","ユ"],["ヨ","ヨ"],["ラ","ラ"],["リ","リ"],["ル","ル"],["レ","レ"],["ロ","ロ"],["ワ","ワ"],["ン","ン"],["゙","゛"],["゚","゜"] ]) }]);
f.push(["全角カナ→半角","R",function(a){
return a.replaceBatch([ ["。","。"],["「","「"],["」","」"],["、","、"],["・","・"],["ヲ","ヲ"],["ァ","ァ"],["ィ","ィ"],["ゥ","ゥ"],["ェ","ェ"],["ォ","ォ"],["ャ","ャ"],["ュ","ュ"],["ョ","ョ"],["ッ","ッ"],["ー","ー"],["ア","ア"],["イ","イ"],["ヴ","ヴ"],["ウ","ウ"],["エ","エ"],["オ","オ"],["ガ","ガ"],["ギ","ギ"],["グ","グ"],["ゲ","ゲ"],["ゴ","ゴ"],["カ","カ"],["キ","キ"],["ク","ク"],["ケ","ケ"],["コ","コ"],["ザ","ザ"],["ジ","ジ"],["ズ","ズ"],["ゼ","ゼ"],["ゾ","ゾ"],["サ","サ"],["シ","シ"],["ス","ス"],["セ","セ"],["ソ","ソ"],["ダ","ダ"],["ヂ","ヂ"],["ヅ","ヅ"],["デ","デ"],["ド","ド"],["タ","タ"],["チ","チ"],["ツ","ツ"],["テ","テ"],["ト","ト"],["ナ","ナ"],["ニ","ニ"],["ヌ","ヌ"],["ネ","ネ"],["ノ","ノ"],["バ","バ"],["ビ","ビ"],["ブ","ブ"],["ベ","ベ"],["ボ","ボ"],["パ","パ"],["ピ","ピ"],["プ","プ"],["ペ","ペ"],["ポ","ポ"],["ハ","ハ"],["ヒ","ヒ"],["フ","フ"],["ヘ","ヘ"],["ホ","ホ"],["マ","マ"],["ミ","ミ"],["ム","ム"],["メ","メ"],["モ","モ"],["ヤ","ヤ"],["ユ","ユ"],["ヨ","ヨ"],["ラ","ラ"],["リ","リ"],["ル","ル"],["レ","レ"],["ロ","ロ"],["ワ","ワ"],["ン","ン"],["゛","゙"],["゜","゚"] ]) }]);
f.push(["標準変換","R",function(a){
return a.replaceBatch([ [" "," "],["!","!"],["“",'"'],["”",'"'],["#","#"],["$","$"],["%","%"],["&","&"],["‘","'"],["’","'"],["(","("],[")",")"],["*","*"],["+","+"],[",",","],["-","-"],[".","."],["/","/"],["0","0"],["1","1"],["2","2"],["3","3"],["4","4"],["5","5"],["6","6"],["7","7"],["8","8"],["9","9"],[":",":"],[";",";"],["<","<"],["=","="],[">",">"],["?","?"],["@","@"],["A","A"],["B","B"],["C","C"],["D","D"],["E","E"],["F","F"],["G","G"],["H","H"],["I","I"],["J","J"],["K","K"],["L","L"],["M","M"],["N","N"],["O","O"],["P","P"],["Q","Q"],["R","R"],["S","S"],["T","T"],["U","U"],["V","V"],["W","W"],["X","X"],["Y","Y"],["Z","Z"],["[","["],["¥","\\"],["]","]"],["^","^"],["_","_"],["`","`"],["a","a"],["b","b"],["c","c"],["d","d"],["e","e"],["f","f"],["g","g"],["h","h"],["i","i"],["j","j"],["k","k"],["l","l"],["m","m"],["n","n"],["o","o"],["p","p"],["q","q"],["r","r"],["s","s"],["t","t"],["u","u"],["v","v"],["w","w"],["x","x"],["y","y"],["z","z"],["{","{"],["|","|"],["}","}"],["~","~"],["。","。"],["「","「"],["」","」"],["、","、"],["・","・"],["ヲ","ヲ"],["ァ","ァ"],["ィ","ィ"],["ゥ","ゥ"],["ェ","ェ"],["ォ","ォ"],["ャ","ャ"],["ュ","ュ"],["ョ","ョ"],["ッ","ッ"],["ー","ー"],["ア","ア"],["イ","イ"],["ヴ","ヴ"],["ウ","ウ"],["エ","エ"],["オ","オ"],["ガ","ガ"],["ギ","ギ"],["グ","グ"],["ゲ","ゲ"],["ゴ","ゴ"],["カ","カ"],["キ","キ"],["ク","ク"],["ケ","ケ"],["コ","コ"],["ザ","ザ"],["ジ","ジ"],["ズ","ズ"],["ゼ","ゼ"],["ゾ","ゾ"],["サ","サ"],["シ","シ"],["ス","ス"],["セ","セ"],["ソ","ソ"],["ダ","ダ"],["ヂ","ヂ"],["ヅ","ヅ"],["デ","デ"],["ド","ド"],["タ","タ"],["チ","チ"],["ツ","ツ"],["テ","テ"],["ト","ト"],["ナ","ナ"],["ニ","ニ"],["ヌ","ヌ"],["ネ","ネ"],["ノ","ノ"],["バ","バ"],["ビ","ビ"],["ブ","ブ"],["ベ","ベ"],["ボ","ボ"],["パ","パ"],["ピ","ピ"],["プ","プ"],["ペ","ペ"],["ポ","ポ"],["ハ","ハ"],["ヒ","ヒ"],["フ","フ"],["ヘ","ヘ"],["ホ","ホ"],["マ","マ"],["ミ","ミ"],["ム","ム"],["メ","メ"],["モ","モ"],["ヤ","ヤ"],["ユ","ユ"],["ヨ","ヨ"],["ラ","ラ"],["リ","リ"],["ル","ル"],["レ","レ"],["ロ","ロ"],["ワ","ワ"],["ン","ン"],["゙","゛"],["゚","゜"] ]) }]);