WSHでExcel内テキスト置換ツールを作るよ

# WSHでExcel内テキスト置換ツールを作るよ
以下に対応してるよ

- セル内テキスト置換
- オートシェイプ内テキスト置換
- 正規表現
- Drag & Dropで、複数ファイル一気に置換

<hr/>

## 本体
<details><summary>XlsxReplace.wsf</summary><div>

```html
// UTF-8(BOM付)で保存すること.
<job>
  <script language="JavaScript" src="CommonUtil.js"></script>
  <script language="JavaScript" src="XlsxUtil.js"></script>
  <script language="JavaScript" src="IeUtil.js"></script>
  <resource id="inputHtml">
    <![CDATA[
      <html>
      <head>
        <meta charset="utf-8"/>
        <style type="text/css">
        <!--
        body { font-family:'メイリオ',Meiryo; }
        ul { padding-left: 0px; list-style-type: none; }
        li[id="wrapper"] { text-align:center; }
        input[type="button"] {
          font-size: 1.4em; font-weight: bold; padding: 10px 30px;
          -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px;
         }
        -->
        </style>
      </head>
      <body>
        <form>
          <input type="hidden" id="CLICKED" value="false"/>
          <ul>
            <li>置換条件入力（正規表現対応）</li>
            <li>対象文字列: <input type="text" id="targetStr"/></li>
            <li>置換文字列: <input type="text" id="replaceStr"/></li>
            <br/>
            <li><input type="checkbox" id="allReplace" checked />該当文字列は全置換する</li>
            <li><input type="checkbox" id="autoShapes" />オートシェイプ内も置換する</li>
            <br/>
            <li id="wrapper">
              <input type="button" onClick="quit()" value="実行"/>
            </li>
          </ul>
        </form>
        <script>
          document.body.style.overflow = "hidden";
          function quit(){
            document.getElementById( "CLICKED" ).value="true";
            window.open('','_self').close();
          }
        </script>
      </body>
      </html>
    ]]>
  </resource>
  <script language="JavaScript">
    // 引数チェック.
    if ( WScript.Arguments.length === 0 ){
      $.info( "ファイルをD&Dしてください.", "エラー" );
      WScript.Quit();
    }

    var displaySize = $.IE.getDisplaySize();
    var replaceInfo = $.IE.displayCustomWindow(
      displaySize.width, displaySize.height, 360, 300, getResource( "inputHtml" ), "置換条件入力"
    );

    // 実行.
    var NewBookPrefix = "new_";
    var reg = new RegExp( replaceInfo.targetStr, replaceInfo.allReplace ? 'g' : '' );
    $.mapX( WScript.Arguments, function( arg ){
      $.Xlsx.withXlsx( arg, function( ole, book ){
        $.mapX( book.Worksheets, function( sheet ){
          if ( replaceInfo.autoShapes ){
            $.Xlsx.replaceShapeValue( sheet, reg, replaceInfo.replaceStr );
          }
          $.Xlsx.replaceCellValue( sheet.usedrange, reg, replaceInfo.replaceStr );
        });

        // saveAs.
        book.Saveas( book.Path + $.FileSeparator + NewBookPrefix + book.Name );
      });
    });

    // 終了.
    $.info( "done.", "end" );
    WScript.Quit();
  </script>
</job>
```
</div></details>
<br/>
## 共通FW
https://qiita.com/onegear0o/items/1dc4a30cf9ec4dd120e0
から、大半流用させてもらってます.
<details><summary>CommonUtil.js</summary><div>

```js
//  CommonUtil.js
//  UTF-8(BOM付)で保存すること.
(function() {
  "use strict";

  var root = this;

  var $ = function( obj ) {
    if ( obj instanceof $ ) return obj;
    if ( !( this instanceof $ ) ) return new $( obj );
    this._wrapped = obj;
  }

  root.$ = $;

  $.Fso = new ActiveXObject( "Scripting.FileSystemObject" );
  $.Shell = new ActiveXObject( "WScript.Shell" );

  $.FileSeparator = "/";
  $.AdoDbStream = {
    obj : new ActiveXObject( "ADODB.Stream" ),

    // StreamTypeEnum.
    adTypeBinary : 1,
    adTypeText : 2,

    // SaveOptionsEnum.
    adSaveCreateNotExist : 1,
    adSaveCreateOverWrite : 2,

    // StreamWriteEnum.
    adWriteChar : 0,
    adWriteLine : 1,
    
    // StreamReadEnum.
    adReadAll : -1,
    adReadLine : -2,
    
    LF : 10,

    // read file with charset.
    readFile : function( fullPath, charset, func ) {
      if ( charset == null ) {
        charset = "_autodetect_all";
      }
      var st = $.AdoDbStream.obj;
      st.Type = $.AdoDbStream.adTypeText;
      st.charset = charset;
      st.LineSeparator = $.AdoDbStream.LF;
      st.Open();
      st.LoadFromFile( fullPath );
      st.Position = 0;
      while( ! st.EOS ){
        func( st.ReadText( $.AdoDbStream.adReadLine ) );
      }
      st.Close();
    },
      
    // write file with charset.
    writeFile : function( fullPath, text, charset ) {
      if ( charset == null ) {
        charset = "_autodetect_all";
      }
      var st = $.AdoDbStream.obj;
      st.Type = $.AdoDbStream.adTypeText;
      st.charset = charset;
      st.Open();
      st.WriteText( text, $.AdoDbStream.adWriteLine );
      st.SaveToFile( fullPath, $.AdoDbStream.adSaveCreateOverWrite );
      st.Close();
    }
  }

  $.yesno = function( message, title ) {
    return $.Shell.Popup( message, 0, title, 1 );
  }

  $.info = function( message, title ) {
    return $.Shell.Popup( message, 0, title, 0 );
  }

  $.log = function( m ) {
    WScript.echo( m );
  }

  // each with activeXObject
  $.eachX = function( obj, func ) {
    for( var _obj = new Enumerator( obj ); !_obj.atEnd(); _obj.moveNext() ){
      var v = _obj.item();
      func( v )
    }
  }

  // map with activeXobject
  $.mapX = function( obj, func ) {
    var ret = [];
    for( var _obj = new Enumerator( obj ); !_obj.atEnd(); _obj.moveNext() ){
      var v = _obj.item();
      var value = func( v );
      if ( !( value === false ) ) ret[ret.length] = value
    }
    return ret;
  }

  $.assignObject = function( obj1, obj2 ) {
    if ( !obj2 ) {
      obj2 = {};
    }
    for ( var attrName in obj2 ) {
      if ( obj2.hasOwnProperty( attrName ) ) {
        obj1[attrName] = obj2[attrName];
      }
    }
    return obj1;
  }

  $.objectkeys = function( obj ) {
    var keys = [];
    for ( var attrName in obj ) {
      if ( obj.hasOwnProperty( attrName ) ) {
        keys.push( attrName );
      }
    }
    return keys;
  }

  $.getZeroPadding = function( number, digits ) {
    return ( Array( digits +1 ).join( '0' ) + number ).slice( -digits );
  }

  $.getDateString = function( date, dateFormat ) {
    var months = [
      "Jan", "Feb", "Mar", "Apr", "May", "Jun",
      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    ];
    var dayOfWeekStr = [ "日", "月", "火", "水", "木", "金", "土" ];
    var dayOfWeekEngStr = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ];
    return dateFormat
      .replace( /@YYYY@/g, date.getFullYear() )
      .replace( /@YY@/g, ( "" + date.getFullYear() ).slice( -2 ) )
      .replace( /@MMM@/g, months[ date.getMonth() ] )
      .replace( /@MM@/g, $.getZeroPadding( date.getMonth() + 1, 2) )
      .replace( /@M@/g, date.getMonth() + 1 )
      .replace( /@DD@/g, $.getZeroPadding( date.getDate(), 2) )
      .replace( /@D@/g, date.getDate() )
      .replace( /@hh@/g, $.getZeroPadding( date.getHours(), 2) )
      .replace( /@h@/g, date.getHours() )
      .replace( /@mm@/g, $.getZeroPadding( date.getMinutes(), 2) )
      .replace( /@m@/g, date.getMinutes() )
      .replace( /@ss@/g, $.getZeroPadding( date.getSeconds(), 2) )
      .replace( /@s@/g, date.getSeconds() )
      .replace( /@EEE@/g, dayOfWeekStr[ date.getDay() ] )
      .replace( /@eee@/g, dayOfWeekEngStr[ date.getDay() ] );
  }

  $.isDate = function( s ){
    var d = new Date( s );
    return d.toString() !== 'NaN' && d.toString() !== 'Invalid Date';
  }

  $.compareDateStr = function( dateStr1, dateStr2 ){
    var date1 = new Date( dateStr1 );
    var date2 = new Date( dateStr2 );
    return date1.getTime() < date2.getTime() ? -1 : date1.getTime() > date2.getTime() ? 1 : 0;
  }

  Array.prototype.indexOf = function(obj, start){ for(var i = (start || 0), j = this.length; i < j; i++){ if(this[i] === obj){ return i }} return -1 };

}).call( this );
```
</div></details>
<br/>
## Excel用FWっぽいの
https://qiita.com/onegear0o/items/1dc4a30cf9ec4dd120e0
から、大半流用させてもらってます.
<details><summary>XlsxUtil.js</summary><div>

```js
//    XlsxUtil.js
// UTF-8(BOM付)で保存すること.
(function () {
  "use strict";

  var root = this;

  if ( typeof $ === "undefined" ) {
    WScript.echo('"CommonUtil.js" must be loaded.');
    WScript.Quit();
  }

  // For Excel.
  $.Xlsx = {
    // XlPageOrientation.
    xlPortrait: 1,
    xlLandscape: 2,

    // XlWindowView.
    xlNormalView: 1,
    xlPageBreakPreview: 2,
    xlPageLayoutView: 3,

    // XlPaperSize.
    xlPaperA3: 8,
    xlPaperA4: 9,
    xlPaperA5: 11,
    xlPaperB4: 12,
    xlPaperB5: 13,

    withXlsx : function ( file_name , func ) {
      var ole = new ActiveXObject( "Excel.Application" );
      ole.Visible = false;
      ole.DisplayAlerts = false;
      var book = null;
      var full_path = null;
      try {
        full_path = $.Fso.getAbsolutePathName( file_name );
        book = ole.Workbooks.Open( full_path );
        func( ole , book );
      } catch( e ) {
        $.log( e.name + ":" + e.message );
      } finally {
        if( book != null){
          book.Close();
        }
        ole.Quit();
      }
    },

    range2hash : function ( range ) {
      var ret = [];
      ret = $.mapX( range.rows , function( row ) {
        var _v = $.mapX( row.columns , function( cell ) {
          var v = cell.value;
          if ( typeof v == "undefined" ) v = "";
          if ( typeof v == "unknown" ) v = "#REF"
            return v;
        })
        return _v;
      })
      return ret;
    },

    range2AddressMap : function ( sheetName ,range ) {
      var ret = {};
      $.mapX( range.rows , function( row ) {
        $.mapX( row.columns , function( cell ) {
          var text = cell.Text;
          if ( text ) ret[sheetName + "!" + cell.Address( false, false )] = text;
        });
      });
      return ret;
    },

    replaceCellValue : function ( range, reg, replaceStr ) {
      $.mapX( range.rows , function( row ) {
        $.mapX( row.columns , function( cell ) {
          var text = cell.Text;
          if ( text ) cell.Value = text.replace( reg, replaceStr );
        });
      });
    },

    replaceShapeValue : function ( sheet, reg, replaceStr ) {
      $.mapX( sheet.Shapes , function( shape ) {
        var text = null;
        try {
          if ( shape.TextFrame2.HasText ){
            text = shape.TextFrame.Characters().Text;
          }
        } catch ( e ) {
          return;
        }
        if ( text ){
          shape.TextFrame.Characters().Text = text.replace( reg, replaceStr );
        }
      });
    }

  }
}).call( this );
```
</div></details>
<br/>
## IE制御用FWっぽいの

<details><summary>IeUtil.js</summary><div>

```js
//    IeUtil.js
// UTF-8(BOM付)で保存すること.
(function () {
  "use strict";

  var root = this;

  if ( typeof $ === "undefined" ) {
    WScript.echo('"CommonUtil.js" must be loaded.');
    WScript.Quit();
  }

  // for catch OnQuit event.
  root.IE_OnQuit = function (){
    $.IE.onQuitWrapper();
  }

  // For IE.
  $.IE = {

    // ReadyState.
    READYSTATE_UNINITIALIZED : 0,
    READYSTATE_LOADING : 1,
    READYSTATE_LOADED : 2,
    READYSTATE_INTERACTIVE : 3,
    READYSTATE_COMPLETE : 4,

    ObjectIE : WScript.CreateObject( "InternetExplorer.Application", "IE_" ),
    SettingInfo : {},
    Clicked : false,

    // IEを閉じた際のエベント処理
    onQuitWrapper : function (){
      var objIe = this.ObjectIE;
      if ( objIe.document.getElementById( "CLICKED" ).value === "true" ){
        // inputタグの処理
        $.mapX( objIe.document.getElementsByTagName( "input" ), function( tag ){
          $.IE.setTagVal( tag, $.IE.SettingInfo );
        });

        // selectタグの処理
        $.mapX( objIe.document.getElementsByTagName( "select" ), function( tag ){
          $.IE.setTagVal( tag, $.IE.SettingInfo );
        });
      }
      this.Clicked = true;
    },

    // IEオブジェクトより、ディスプレイサイズ(Widht, Height)を取得する.
    getDisplaySize : function ( path ){
      var objIe = WScript.CreateObject( "InternetExplorer.Application" );
      this.Clicked = false;
      this.SettingInfo = {};
      objIe.Visible = false;
      objIe.Navigate( "about:blank" );
      this.waitIE( objIe );
      var width = objIe.document.parentWindow.screen.width;
      var height = objIe.document.parentWindow.screen.height;
      objIe.Quit();
      return { "width": width, "height": height };
    },

    // IEのオブジェクトを作り、画面の設定をして、表示.
    // HtmlのInputタグ入力値を返却
    displayCustomWindow : function (
      displayWidth,
      displayHeight,
      windowWidth,
      windowHeight,
      html,
      title
    ){
      var objIe = this.ObjectIE;
      this.Clicked = false;
      this.SettingInfo = {};
      objIe.Left = ( displayWidth - windowWidth ) / 2;
      objIe.Top = ( displayHeight - windowHeight ) / 2;
      objIe.Width = windowWidth;
      objIe.Height = windowHeight;
      objIe.ToolBar = false;
      objIe.StatusBar = false;
      objIe.Resizable = true;
      objIe.Visible = true;
      objIe.Navigate( "about:blank" );
      this.waitIE( objIe );

      objIe.document.write( html );
      objIe.document.title = title;

      // ボタンクリック待ち.
      while ( ! this.Clicked ) { WScript.Sleep(500) }

      // 判定.
      if ( ! $.objectkeys( $.IE.SettingInfo ).length ){
        WScript.quit();
      }

      return $.IE.SettingInfo;
    },

    // IEがビジー状態の間待ちます.
    waitIE : function ( objIe ){
      while( ( objIe.Busy ) || ( objIe.readystate != this.READYSTATE_COMPLETE ) ){
        WScript.Sleep( 100 );
      }
    },

    // set Tag-Value.
    setTagVal : function ( tag, ret ){
      switch ( tag.type.toLowerCase() ){
        case "text":
          ret[ tag.id ] = tag.value;
          break;
        case "checkbox":
          ret[ tag.id ] = tag.checked;
          break;
        case "radio":
          ret[ tag.name ] = tag.checked ? tag.value : ret[ tag.name ];
          break;
        case "select-one":
          ret[ tag.id ] = tag.value;
          break;
        default:
          // Do Nothing.
          break;
      }
      return ret;
    }
  }
}).call( this );
```
</div></details>
<br/>
## 統合版
面倒な人はこれをローカルにコピペして使ってください。

<details><summary>XlsxReplace.wsf</summary><div>

```js
// UTF-8(BOM付)で保存すること.
<job>
  <script language="JavaScript">
    (function(){"use strict";var e=function(t){return t instanceof e?t:this instanceof e?void(this._wrapped=t):new e(t)};this.$=e,e.Fso=new ActiveXObject("Scripting.FileSystemObject"),e.Shell=new ActiveXObject("WScript.Shell"),e.FileSeparator="/",e.AdoDbStream={obj:new ActiveXObject("ADODB.Stream"),adTypeBinary:1,adTypeText:2,adSaveCreateNotExist:1,adSaveCreateOverWrite:2,adWriteChar:0,adWriteLine:1,adReadAll:-1,adReadLine:-2,LF:10,readFile:function(t,a,n){null==a&&(a="_autodetect_all");var r=e.AdoDbStream.obj;for(r.Type=e.AdoDbStream.adTypeText,r.charset=a,r.LineSeparator=e.AdoDbStream.LF,r.Open(),r.LoadFromFile(t),r.Position=0;!r.EOS;)n(r.ReadText(e.AdoDbStream.adReadLine));r.Close()},writeFile:function(t,a,n){null==n&&(n="_autodetect_all");var r=e.AdoDbStream.obj;r.Type=e.AdoDbStream.adTypeText,r.charset=n,r.Open(),r.WriteText(a,e.AdoDbStream.adWriteLine),r.SaveToFile(t,e.AdoDbStream.adSaveCreateOverWrite),r.Close()}},e.yesno=function(t,a){return e.Shell.Popup(t,0,a,1)},e.info=function(t,a){return e.Shell.Popup(t,0,a,0)},e.log=function(e){WScript.echo(e)},e.eachX=function(e,t){for(var a=new Enumerator(e);!a.atEnd();a.moveNext()){t(a.item())}},e.mapX=function(e,t){for(var a=[],n=new Enumerator(e);!n.atEnd();n.moveNext()){var r=t(n.item());!1!==r&&(a[a.length]=r)}return a},e.assignObject=function(e,t){for(var a in t||(t={}),t)t.hasOwnProperty(a)&&(e[a]=t[a]);return e},e.objectkeys=function(e){var t=[];for(var a in e)e.hasOwnProperty(a)&&t.push(a);return t},e.getZeroPadding=function(e,t){return(Array(t+1).join("0")+e).slice(-t)},e.getDateString=function(t,a){return a.replace(/@YYYY@/g,t.getFullYear()).replace(/@YY@/g,(""+t.getFullYear()).slice(-2)).replace(/@MMM@/g,["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][t.getMonth()]).replace(/@MM@/g,e.getZeroPadding(t.getMonth()+1,2)).replace(/@M@/g,t.getMonth()+1).replace(/@DD@/g,e.getZeroPadding(t.getDate(),2)).replace(/@D@/g,t.getDate()).replace(/@hh@/g,e.getZeroPadding(t.getHours(),2)).replace(/@h@/g,t.getHours()).replace(/@mm@/g,e.getZeroPadding(t.getMinutes(),2)).replace(/@m@/g,t.getMinutes()).replace(/@ss@/g,e.getZeroPadding(t.getSeconds(),2)).replace(/@s@/g,t.getSeconds()).replace(/@EEE@/g,["日","月","火","水","木","金","土"][t.getDay()]).replace(/@eee@/g,["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][t.getDay()])},e.isDate=function(e){var t=new Date(e);return"NaN"!==t.toString()&&"Invalid Date"!==t.toString()},e.compareDateStr=function(e,t){var a=new Date(e),n=new Date(t);return a.getTime()<n.getTime()?-1:a.getTime()>n.getTime()?1:0},e.Xlsx={xlPortrait:1,xlLandscape:2,xlNormalView:1,xlPageBreakPreview:2,xlPageLayoutView:3,xlPaperA3:8,xlPaperA4:9,xlPaperA5:11,xlPaperB4:12,xlPaperB5:13,withXlsx:function(t,a){var n=new ActiveXObject("Excel.Application");n.Visible=!1,n.DisplayAlerts=!1;var r=null,i=null;try{i=e.Fso.getAbsolutePathName(t),a(n,r=n.Workbooks.Open(i))}catch(t){e.log(t.name+":"+t.message)}finally{null!=r&&r.Close(),n.Quit()}},range2hash:function(t){return e.mapX(t.rows,function(t){return e.mapX(t.columns,function(e){var t=e.value;return void 0===t&&(t=""),"unknown"==typeof t&&(t="#REF"),t})})},range2AddressMap:function(t,a){var n={};return e.mapX(a.rows,function(a){e.mapX(a.columns,function(e){var a=e.Text;a&&(n[t+"!"+e.Address(!1,!1)]=a)})}),n},replaceCellValue:function(t,a,n){e.mapX(t.rows,function(t){e.mapX(t.columns,function(e){var t=e.Text;t&&(e.Value=t.replace(a,n))})})},replaceShapeValue:function(t,a,n){e.mapX(t.Shapes,function(e){var t=null;try{e.TextFrame2.HasText&&(t=e.TextFrame.Characters().Text)}catch(e){return}t&&(e.TextFrame.Characters().Text=t.replace(a,n))})}},this.IE_OnQuit=function(){e.IE.onQuitWrapper()},e.IE={READYSTATE_UNINITIALIZED:0,READYSTATE_LOADING:1,READYSTATE_LOADED:2,READYSTATE_INTERACTIVE:3,READYSTATE_COMPLETE:4,ObjectIE:WScript.CreateObject("InternetExplorer.Application","IE_"),SettingInfo:{},Clicked:!1,onQuitWrapper:function(){var t=this.ObjectIE;"true"===t.document.getElementById("CLICKED").value&&(e.mapX(t.document.getElementsByTagName("input"),function(t){e.IE.setTagVal(t,e.IE.SettingInfo)}),e.mapX(t.document.getElementsByTagName("select"),function(t){e.IE.setTagVal(t,e.IE.SettingInfo)})),this.Clicked=!0},getDisplaySize:function(e){var t=WScript.CreateObject("InternetExplorer.Application");this.Clicked=!1,this.SettingInfo={},t.Visible=!1,t.Navigate("about:blank"),this.waitIE(t);var a=t.document.parentWindow.screen.width,n=t.document.parentWindow.screen.height;return t.Quit(),{width:a,height:n}},displayCustomWindow:function(t,a,n,r,i,o){var c=this.ObjectIE;for(this.Clicked=!1,this.SettingInfo={},c.Left=(t-n)/2,c.Top=(a-r)/2,c.Width=n,c.Height=r,c.ToolBar=!1,c.StatusBar=!1,c.Resizable=!0,c.Visible=!0,c.Navigate("about:blank"),this.waitIE(c),c.document.write(i),c.document.title=o;!this.Clicked;)WScript.Sleep(500);return e.objectkeys(e.IE.SettingInfo).length||WScript.quit(),e.IE.SettingInfo},waitIE:function(e){for(;e.Busy||e.readystate!=this.READYSTATE_COMPLETE;)WScript.Sleep(100)},setTagVal:function(e,t){switch(e.type.toLowerCase()){case"text":t[e.id]=e.value;break;case"checkbox":t[e.id]=e.checked;break;case"radio":t[e.name]=e.checked?e.value:t[e.name];break;case"select-one":t[e.id]=e.value}return t}}}).call(this);
  </script>
  <resource id="inputHtml">
    <![CDATA[<html><head><meta charset="utf-8"/><style type="text/css">body{font-family:'メイリオ',Meiryo}ul{padding-left:0px;list-style-type:none}li[id="wrapper"]{text-align:center}input[type="button"]{font-size:1.4em;font-weight:bold;padding:10px 30px;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}</style></head><body><form> <input type="hidden" id="CLICKED" value="false"/><ul><li>置換条件入力（正規表現対応）</li><br/><li><label for="targetStr">対象文字列: </label><input type="text" id="targetStr"/></li><li><label for="replaceStr">置換文字列: </label><input type="text" id="replaceStr"/></li> <br/><li><input type="checkbox" id="allReplace" checked /><label for="allReplace">該当文字列は全置換する</label></li><li><input type="checkbox" id="autoShapes" /><label for="autoShapes">オートシェイプ内も置換する</label></li><br/><li id="wrapper"><input type="button" onClick="quit()" value="実行"/></li></ul></form> <script>document.body.style.overflow="hidden";function quit(){document.getElementById("CLICKED").value="true";window.open('','_self').close();}</script> </body></html>]]>
  </resource>
  <script language="JavaScript">
    // 引数チェック.
    if ( WScript.Arguments.length === 0 ){
      $.info( "ファイルをD&Dしてください.", "エラー" );
      WScript.Quit();
    }

    // const.
    var XlsxPrefix = "$.Xlsx.";
    var OutputPrefix = "REP";

    var displaySize = $.IE.getDisplaySize();
    var replaceInfo = $.IE.displayCustomWindow(
      displaySize.width, displaySize.height, 400, 380, getResource( "inputHtml" ), "置換条件入力"
    );

    // create folder.
    var dir = $.Fso.GetFile( WScript.Arguments.Item(0) ).ParentFolder + $.FileSeparator +
      OutputPrefix + $.getDateString( new Date(), '@YYYY@@MM@@DD@@hh@@mm@@ss@' );
    if ( !$.Fso.FolderExists( dir ) ){
      $.Fso.CreateFolder( dir );
    }

    // 実行.
    var reg = new RegExp( replaceInfo.targetStr, replaceInfo.allReplace ? 'g' : '' );
    $.mapX( WScript.Arguments, function( arg ){
      $.Xlsx.withXlsx( arg, function( ole, book ){
        $.mapX( book.Worksheets, function( sheet ){
          if ( replaceInfo.autoShapes ){
            $.Xlsx.replaceShapeValue( sheet, reg, replaceInfo.replaceStr );
          }
          $.Xlsx.replaceCellValue( sheet.usedrange, reg, replaceInfo.replaceStr );
        });

        // saveAs.
        book.Saveas( dir + $.FileSeparator + book.Name );
      });
    });

    // 終了.
    $.info( "done.", "end" );
    WScript.Quit();
  </script>
</job>
```
</div></details>

## 総括・ハマりポイント
- 入力用HTMLに懲りすぎてしまった。
- とにかくデバッグがやりづらかった。
- HTMLの中の<\/script>でエスケープが必要なことに気づけず少しはまった。
- WSHファイルだと色々外部化してImportすればいいので、構造が見やすくなる印象。
- 次は、Excelの簡易差分表示できるのが欲しい
- 最高に綺麗なソースにしたいけど、これが限界。
- IE側処理終了時（ボタンや×ボタン押下時）にIEオブジェクトの解放がうまくいかず、<br/>
処理自体は正常終了するもののエラーになる場合がある。<br/>
⇒Enumerator にIEオブジェクトを入れるとその後Quit時にエラーとなる。参照が切れてない？<br/>
<pre>
仮調査結果：
○　getElementById, getElementsByTagName
×　querySelectorAll
</pre>