Skip to content

Instantly share code, notes, and snippets.

@JunichiMuto
Last active October 25, 2016 07:01
Show Gist options
  • Save JunichiMuto/e9376fa4a35d6dd2ab23 to your computer and use it in GitHub Desktop.
Save JunichiMuto/e9376fa4a35d6dd2ab23 to your computer and use it in GitHub Desktop.
Excel検索ツール
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script language="JScript">
/**
Excel検索ツール
auther:J.Muto
リポジトリを作りました!!!
最新版はこちらを参照下さい。
https://github.com/JunichiMuto/ExcelScriptTools
◇ 概要 ◇
指定したディレクトリ内にあるExcelファイルから、
検索キーワードを含むファイルを検索し、表示します。
◇ 動作条件 ◇
IE11+Excel2013にて確認。
IE以外では動きません。
◇ インストール ◇
解凍してできたhtmlファイルを、ローカルディスク上の任意の場所に配置してください。
特に設定等はありません。
(ネットワークドライブ上だとセキュリティ設定により動作しません)
開くとActiveXの警告が出ますが、OKを押してください。
*/
var excel;
try{
excel = new ActiveXObject("Excel.Application");
}catch(e){
alert("IEにて、ローカルで実行してください");
}
excel.EnableEvents = false;//マクロ無効化
var fso = new ActiveXObject("Scripting.FileSystemObject");
var files = new Array();//ファイル名を格納する配列
var isCancel = false; //キャンセルされたか
var count = 0; //ヒット数
var option = "g"; //正規表現オプション
var enableCell = false; //セル検索
var enableShape = false; //オートシェイプ
var enableComment = false; // コメント
var SPAN_RED = "<span style='color:red;'>$1</span>";
//エントリーポイント
function main(){
//入力チェック
var path = document.getElementById("path").value;
var key = document.getElementById("key").value;
if(path == ""){
alert("パスを入力してください");
return;
}
if(key == ""){
alert("キーワードを入力してください");
return;
}
switchForms();
//大文字小文字区別するかどうかでオプションを変更
if(document.getElementById("case").checked){
option = "gi";//グローバル、大文字小文字区別しない
}
isCancel = false;
clearList();
excel.Visible = false;
//検索対象
enableCell = document.getElementById("cell").checked;
enableShape = document.getElementById("shape").checked;
enableComment = document.getElementById("comment").checked;
document.getElementById("status").innerText = "対象ファイルをリストアップ中";
//初期化
files = new Array();
count = 0;
//ここで一旦IEに制御を返す
setTimeout("filesearch()", 500);
}
function filesearch(){
var path = document.getElementById("path").value;
var key = document.getElementById("key").value;
//対象ファイルを検索する
searchFolders(fso.getFolder(path));
if(files.length == 0){
alert("対象ファイルはありません。");
document.getElementById("status").innerText = "対象ファイルなし";
switchForms();
return;
}
//ここで一旦IEに制御を返す
setNext(-1);
}
//対象ファイルのリストアップ
function searchFolders(topfolder){
var e = new Enumerator(topfolder.SubFolders);
for(;!e.atEnd(); e.moveNext()){
var folder = e.item();
searchFolders(folder);
}
e = new Enumerator(topfolder.Files);
for(;!e.atEnd(); e.moveNext()){
var filename = e.item().Path;
if(filename.match(/\.xlsx?$/i)){//xlsとxlsx
files.push(filename);
}
}
}
function searchMain(index){
if(isCancel){
alert("キャンセルしました。");
document.getElementById("status").innerText = "キャンセル";
switchForms();
return;
}
index -= 0;//数値化
var path = files[index];
var key = document.getElementById("key").value;
var pass = document.getElementById("pass").value;
var book;
try{
book = excel.Workbooks.Open(path, 0, true, 5, pass);
}catch(e){
createList("ファイルオープンに失敗", "", "", "", path);
setNext(index);
return;
}
for(var j = 1; j <= book.WorkSheets.Count; j++){
var sheet = book.WorkSheets(j);
console.log("シート:" + sheet.Name);
if(enableCell){
console.log("セル検索");
searchCells(book, sheet, path, key);
}
if(enableShape){
console.log("シェイプ検索");
searchShapes(book, sheet, path, key);
}
if(enableComment){
console.log("コメント検索");
searchComments(book, sheet, path, key);
}
//sheetオブジェクトを明示的に無効にしないとメモリをどんどん消費するようなので予防
//(スコープ外れて無効になるはずなのだけども・・・)
sheet = null;
}
book.Close(false);
setNext(index);
}
//ステータスの更新と次ファイル実行のスケジューリング
function setNext(index){
var obj = document.getElementById("status");
index++;
if(index < files.length){
//ステータスの更新を描画するため、間欠実行にして定期的にIEに制御を戻す
setTimeout("searchMain(" + (index) + ")", 500);
obj.innerText = (index+1) + "/" + files.length +"ファイル処理中... " + files[index];
}else{
alert("完了しました。\n" + count + "件ヒットしました。");
obj.innerText = "完了 " + count + "件ヒットしました";
switchForms();
}
}
//セルの検索
function searchCells(book, sheet, path, key){
var range = sheet.UsedRange;
if(!range) return;
if(excel.WorksheetFunction.CountA(range) == 0){
console.log("空のシートなので飛ばす ");
return;
}
//リストがあると結合解除がうまくいかないので削除
for(var i = 1; i <= sheet.ListObjects.Count; i++){
sheet.ListObjects(i).Delete();
}
//結合を解除(共有されている場合は解除できない)
if(!book.MultiUserEditing){
range.UnMerge();
}
//非表示、オートフィルタを解除
if(document.getElementById("hide").checked){
sheet.Columns.Hidden = false;
sheet.Rows.Hidden = false;
sheet.AutoFilterMode = false;
}
var reg = new RegExp("("+key+")", option);
//rangeがただ1つのセルの場合、ValueはstringとなってVBArrayが生成できない
if(typeof range.Value == "string"){
var text = range.Value;
if(text && reg.test(text)){
text = text.replace(reg, SPAN_RED);
createList(book.Name, sheet.Name, "セル(" + range.Address + ")",
text, path, range.Address);
}
return;
}
//Range#ValueはJavaScriptだとうまく取得できないのでVBArrayにする
var vbrange = new VBArray(range.Value);
for(var i = vbrange.lbound(1), xlen = vbrange.ubound(1); i < xlen; i++){
for(var j = vbrange.lbound(2), ylen = vbrange.ubound(2); j < ylen; j++){
var text = vbrange.getItem(i,j);
if(text && reg.test(text)){
text = text.replace(reg, SPAN_RED);
var cell = range.Cells(i,j);
createList(book.Name, sheet.Name, "セル(" + cell.Address + ")",
text, path, cell.Address);
}
}
}
}
//オートシェイプの検索
function searchShapes(book, sheet, path, key){
var shps = sheet.Shapes;
if(!shps) return;
//グループを解除
//結合を解除(共有されている場合は解除できない)
if(!book.MultiUserEditing){
for(var i = 1; i <= shps.Count; i++){
var item = shps.Item(i);
if(item.Type == 6){
ungroup(item);
}
}
}
var reg = new RegExp("("+key+")", option);
shps = sheet.Shapes;
for(var i = 1; i <= shps.Count; i++){
var item = shps.Item(i);
//MsoShapeType オートシェイプ(1) コールアウト(2)(ふき出し?) テキストボックス(17)
if(item.Type == 1 || item.Type == 2 || item.Type == 17){
var text;
try{
//Charactersが失敗する時があるので例外捕捉
text = item.TextFrame.Characters().Text;
}catch(e){
continue;
}
if(text && reg.test(text)){
text = text.replace(reg, SPAN_RED);
createList(book.Name, sheet.Name,
"オートシェイプ(" + item.TopLeftCell.Address + ")",
text, path, item.TopLeftCell.Address);
}
}
}
}
//グループ化を全て解除
//解除するとオートシェイプが増えるので自動的に対象となる
function ungroup(obj){
if(obj && obj.Type == 6){
var obj = obj.Ungroup();
for(var i = 1; i <= obj.Count; i++){
ungroup(obj.Item(i));
}
}
}
//コメントの検索
function searchComments(book, sheet, path, key){
var cmnts = sheet.Comments;
if(!cmnts) return;
var reg = new RegExp("("+key+")", option);
for(var i = 1; i <= cmnts.Count; i++){
var item = cmnts.Item(i);
var text;
try{
//Charactersが失敗する時があるので例外捕捉
text = item.Shape.TextFrame.Characters().Text;
}catch(e){
continue;
}
if(text && reg.test(text)){
text = text.replace(reg, SPAN_RED);
createList(book.Name, sheet.Name,
"コメント(" + item.Parent.Address + ")", text, path, item.Parent.Address);
}
}
}
//リストの生成
function createList(file, sheet, type, text, path, addr){
count++;
var tr = document.createElement("tr");
var td0 = document.createElement("td");
var td1 = document.createElement("td");
var td2 = document.createElement("td");
var td3 = document.createElement("td");
var td4 = document.createElement("td");
var td5 = document.createElement("td");
td0.innerText = count;
td1.innerText = file;
td2.innerText = sheet;
td3.innerText = type;
td4.innerHTML = text;
//開くボタン パスの\が1つだと消えてしまうので、二重に変換する
var pass = document.getElementById("pass").value;
td5.innerHTML = path + "<input type='button' value='開く' " +
"onclick='openDocument(\"" + path.replace(/\\/g, "\\\\")
+ "\",\"" + pass + "\",\"" + sheet + "\",\"" + addr + "\")' disabled='disabled'>";
tr.appendChild(td0);
tr.appendChild(td1);
tr.appendChild(td2);
tr.appendChild(td3);
tr.appendChild(td4);
tr.appendChild(td5);
var table = document.getElementById("tb");
table.appendChild(tr);
}
//開くボタンの処理
function openDocument(path, pass, sheet, addr){
//開いていた場合は閉じる
if(excel.ActiveWorkbook){
excel.ActiveWorkbook.Close(false);
}
var book;
try{
//Excelオブジェクトは閉じられても死なないので使いまわす
book = excel.Workbooks.Open(path, 0, true, 5, pass);
}catch(e){
alert("ファイルが開けませんでした。");
return;
}
//先に表示して徐々にアクティブ化する(エラー防止)
excel.Visible = true;
var sht = book.WorkSheets(sheet);
sht.Activate();
sht.Range(addr).Activate();
}
function onCancel(){
isCancel = true;
}
function clearList(){
var table = document.getElementById("tb");
var childs = table.childNodes;
//逆順に消していかないとおかしくなるため逆にループ
for(var i = childs.length - 1; i > 0; i--){
table.removeChild(childs[i]);
}
count = 0;
document.getElementById("status").innerText = "キャンセルしました。";
}
//キャンセル以外の無効化・有効化切り替え
function switchForms(){
var forms = document.getElementsByTagName("input");
for(var i = 0; i < forms.length; i++){
if(forms[i].id != "cancel"){
forms[i].disabled = !forms[i].disabled;
}
}
}
</script>
</head>
<body onUnload="excel.Quit();">
Excelドキュメント検索ツール<br>
<div style="color:red;">
<ul>
<li>検索中に裏でExcelを起動しないでください。検索中の状態が表示されてしまいます。</li>
<li>止めるときは強制終了せず、キャンセルボタンを押して待ってください。すぐには止まりません。</li>
<li>強制終了した場合はExcelのプロセスが残っているのでタスクマネージャで終了してください。</li>
<li>英字の全角半角は区別します。</li>
<li>検索結果の開くボタンで開いた場合は読み取り専用になります。また再度押すと既に開いていたファイルを閉じます。</li>
<li>共有ブックでは結合セル内の文字列を検索できません。</li>
</ul>
</div>
<br>
<table border="1">
<tr>
<td>キーワード:</td><td><input id="key" type="text" size="50"/></td>
</tr>
<tr>
<td>パス:</td><td><input id="path" type="text" size="100"/></td>
</tr>
<tr>
<td>パスワードが必要な場合:</td><td><input id="pass" type="password"/></td>
</tr>
<tr>
<td>検索対象:</td><td><input id="cell" type="checkbox" checked="checked"/>セル <input id="shape" type="checkbox" checked="checked"/>オートシェイプ <input id="comment" type="checkbox" checked="checked"/>コメント</td>
<tr>
<td colspan="2">
<input id="case" type="checkbox" checked="checked"/>大文字小文字を区別しない(英字)<br>
<input id="hide" type="checkbox" checked="checked"/>非表示、オートフィルタの隠し部分を検索する
</td>
</tr>
<tr>
<td colspan="2" align="right"><input id="search" type="button" value="検索" onclick="main();"/> <input id="cancel" type="button" value="キャンセル" onclick="onCancel();"/>
</tr>
</table>
<br>
ステータス:<span id="status"></span><br>
<br>
<table border="1">
<thead>
<tr>
<th></th><th>ファイル名</th><th>シート名</th><th>種別</th><th>内容</th><th>パス</th>
</tr>
</thead>
<tbody id="tb">
</tbody></table></body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment