Syntax Highliterでソースコードを表示するときは、エスケープ処理してから張り付けなくてはいけない。そうしないと、たとえばC++のテンプレート定義とかはHTMLタグとして認識されてしまうからだ。今まではエディタの置換処理でエスケープしていたのだけれど、面倒くさいので、クリップボードにコピーしたものをエスケープするコードを書いてみた。
JavaScript(WSH)で行う方法
手っ取り早くJavaScriptで作れないかとググってみると「WSH よりクリップボード、次の手」というページに行き着いた。IE経由でクリップボードにアクセスする方法だ。これを使って作ったのが下のプログラムである。
<job id="EscapeClipboardText">
<script language="JScript">
var jp;
if (!jp) jp = {};
if (!jp.raindrop) jp.raindrop = {};
if (!jp.raindrop.frog) jp.raindrop.frog = {};
jp.raindrop.frog.clipboard || (function ()
{
// コマンドのID
var OLECMDID_COPY = 12;
var OLECMDID_PASTE = 13;
var OLECMDID_SELECTALL = 17;
// IE の初期化
var _internetExplorer = new ActiveXObject ('InternetExplorer.Application');
_internetExplorer.navigate ("about:blank");
while (_internetExplorer.Busy)
WScript.Sleep (10);
// textarea 要素を作成する
var _textarea = _internetExplorer.document.createElement ("textarea");
_internetExplorer.document.body.appendChild (_textarea);
_textarea.focus ();
jp.raindrop.frog.clipboard = {
// クリップボードに文字列をコピー
setText: function (text)
{
_textarea.innerText = text;
_internetExplorer.execWB (OLECMDID_SELECTALL, 0);
_internetExplorer.execWB (OLECMDID_COPY, 0);
},
// クリップボードより文字列を取得
getText: function ()
{
_textarea.innerText = "";
_internetExplorer.execWB (OLECMDID_PASTE, 0);
return _textarea.innerText;
},
// IE を解放
release: function ()
{
_internetExplorer.Quit ();
}
};
}());
var data = jp.raindrop.frog.clipboard.getText ();
data = data.replace(/\&/ig,'&amp;');
data = data.replace(/\>/ig,'&gt;');
data = data.replace(/\</ig,'&lt;');
data = data.replace(/\"/ig,'&quot;');
jp.raindrop.frog.clipboard.setText (data);
</script>
</job>
しかし私の環境で実行すると下記ウィンドウが表示されてしまう。しかしエスケープはきちんとされていた。
ブラウザがIE10のせいかもしれないね。。さてどうしたものか。。
C++で作り直す
考え直すとそもそもクリップボードAPIを直接使うほうが簡単じゃないか。C++でつくればすぐできるなということで作ったのが下記コードである。文字列置換部分はS34サイトの「’置換’はどうやればいいのですか?」を 参考にした。
//
// escapeclipboard.cpp : クリップボードの中身をエスケープする
//
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <WindowsX.h>
#include <string>
std::wstring replace(const std::wstring& source,const std::wstring& pattern,const std::wstring& placement){
std::wstring result(source);
for ( std::wstring::size_type pos = 0 ;
std::wstring::npos != (pos = result.find(pattern,pos));
pos += placement.size() )
result.replace(pos, pattern.size(), placement);
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
::OpenClipboard(NULL);
HANDLE text = GetClipboardData(CF_UNICODETEXT);
if(text)
{
std::wstring clip_text((wchar_t*)::GlobalLock(text));
GlobalUnlock(text);
std::wstring replaced_data;
replaced_data = replace(clip_text,L"&",L"&amp;");
replaced_data = replace(replaced_data,L"<",L"&lt;");
replaced_data = replace(replaced_data,L">",L"&gt;");
replaced_data = replace(replaced_data,L"\"",L"&quot;");
replaced_data = replace(replaced_data,L"'",L"&#39;");
HGLOBAL replaced_data_handle = ::GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,sizeof(wchar_t) * (replaced_data.length() + 1));
wchar_t* dest = (wchar_t*)GlobalLock(replaced_data_handle);
ZeroMemory(dest,sizeof(wchar_t) * (replaced_data.length() + 1));
std::copy(replaced_data.begin(),replaced_data.end(),dest);
GlobalUnlock(replaced_data_handle);
EmptyClipboard();
SetClipboardData(CF_UNICODETEXT,replaced_data_handle);
CloseClipboard();
}
return 0;
}
こっちのほうが簡単にできたな。。