#A
VBScriptの基本 Csvファイルの処理方法など 

 
 htmlの仕様は、インターネットの表示画面の作成ツールですが、個人のパソコンで利用するWindow画面型プログラムを作成する容易な手段となります。これは現在では htaプリグラムとして利用が盛んになっています。
 実際に、画面作成にはhtmlの仕様ほど平易で楽に画面レイアウトを編集できる言語は他にありません。 画面表示にレコードデータの仕組みを組み合わせれば、多くのデータや画像を表示できる仕組みが、htmlの知識の延長で作成できます。
  データ管理には、CSVなどのファイルデータ処理が必要です。
 このページは、ファイル処理の地道な技法面の紹介です。バックヤード(裏庭の)仕事として、基本的な事項を紹介します。
 このページだけで、VBScriptの記述が容易になるように、今後も情報データを追記します。

#B
 データベースと二元配列

 最も簡単なデータベースはテーブルです。テーブルは列と行から構成されています。テーブルのデータは一般的には二元配列データとして扱います。したがって、データべ-スを扱うには二元配列でのデータ処理の知識が必要となります。
 しかし、多くのテキストでは配列として一元配列の操作は紹介されていますが、二元配列での具体的な記述方法の例示は多くありません。 このページでは散在する二元配列の操作にかんする記述を覚書としてまとめたものです。
 htmlで使用するデータベースデータは、html内において処理する場合とhtmlとは別なデータファイルを作成し、これらの外部ファイルを読み込み、参照する場合があります。 
 前者はJavaScriptとその一種の方言であるjQueryで処理します。後者の場合は操作の楽なVBScriptで操作します。そのため、JavaScriptとVBScriptの双方での二元配列の記述法を述べることとします。

#C
 JavaScriptでの配列の記述法
 
 JavaScriptには、通常の配列と連想配列があります。 通常の配列の標準は一元配列で、二元配列は、「配列の配列」として記述します。
  (「配列リテラルオブジェクトリテラルとeval」を参照 (http://d.hatena.ne.jp/chaichanPaPa/20080513/1210677748))

 [配列の宣言]
var qA = new Array(100);  //qAという名の100要素の配列を宣言します。
var qB = new Array( );      //( ) 内に数値いれなくても問題はありません。要素数は自由です。
 [配列の初期値の設定] 
var qA = [ 13, 24, 35, 46, 58 ] ;                      //数値は数字を記述します。
var qB = [ "Ca", "Na", "Au", "Fe" ] ;             //文字列は" "か'  'で括ります。
var qC = [ "Alison", "Ret", "large", 1955 ] ;   //文字列と数値を混在してもよい。
 [配列への代入と参照]
var qD = new Array( ) ;
qD[ 0] = 23;
qD[ 1] ="Bob";
qD[ 2] =1933;
var strAns1 = qD[ 2] ;
var strAns2 = qD[ 0] ;
document.write( strAns1 +"<br>");
document.write( strAns2 +"<br>"); 
 [配列全体の参照]
var qC = [ "Alison", "Ret", "large", 1955 ] ; 
var strAns3 = qC;                           //配列名を文字列に代入すると
document.write( strAns31 +"<br>");    //全要素がカンマ区切りで表示される。

 [二元配列の宣言と初期値の設定]
var qA2 = new Array( );
qA2[ 0] = new Array( );     //一次配列の各要素に
qA2[ 1] = new Array( );     //それぞれ配列を宣言する。
qA2[ 0][ 0] = 4;              //配列にデータをセット
qA2[ 0][ 1] = 5;
qA2[ 0][ 1] = 6;             
qA2[ 1][ 0] = 41;           
qA2[ 1][ 1] = 51;
qA2[ 1][ 1] = 61; 
 
var qData = new Array( );               //ループで値を代入
for( var i = 0; i<9; i ++ ) {
     qData[ i ] = new Array( );
     for ( var j = 0; j<9; j++ ) {
         qData[ i ][ j ] = i * 10 + j;
     }
}

  [二元配列の宣言と初期値の設定]  データを一括設定
var qA = [ [ 2, 3, 4, 5],[ 6, 7, 8, 9],[ 5, 5, 6, 7] ];
document.write( qA[1][2]+"<br>"+"<br>");

var qA = [ [ 2,  3,   4,   5],             //改行して記述するとテーブル型となり分かりやすい
        [12, 13, 14, 15],
              [22, 23, 24, 25]
            ];
for(var i=0; i<qA.length; i++) {
   for(var j=0; j<qA[ i ].length; j++) {
       document.write( qA[ i ][ j ]+",");
   }
   document.write( "<br>");
}
document.write( "<br><br>");

var qA = [ [ 2,  3,   4,   5],             //改行して記述するとテーブル型となり分かりやすい
        [12, 13, 14, 15],
              [22, 23, 24, 25]
            ];
var sAns = "";
for(var i=0; i<qA.length; i++) {
   sAns = sAns + qA[i] + "<br>"      //qA[ 0], qA[ 1], qA[ 2] を文字列として結合
}
document.write( sAns + "<br><br>");


#C1
 JavaScriptの配列の操作・関数

                                       参照例 : http://www.tohoho-web.com/js/array.htm
 JavaScriptには、操作には、Arrayクラスのプロパティ、メソッドによります。

       qRec[ ][ ] の二元配列での記述例    qPre [ ] :一元配列
   [ length ]  配列数を返す         n1 = qRec.length (一次配列数)    n2 = qRec[3].length (ニ次配列数) 
   [ join     ]  配列の全要素を引数で指定した文字で連結した文字列を作成する。
              sAns = qRec.( \n );
      [ reverse ]  配列を逆順に並び替えその結果の配列を返します。   qRev = qPre.reverse;
      [ sort      ] 配列をソートした配列を返す。                                qSort = qPre.reverse;
      [ delete   ]  要素としての配列を削除する。                                delte qRec;
      [ concat  ]   配列Aに配列Bを結合する。   qC = qA.concat( qB) ;  
                             qRecTitle[0]=qFjname;   qRecJ = qRecTitle.concat(qRec);  //二元配列の結合headを付ける
   [  push     ]   配列の最後に最後に配列要素を加えます。  qPre.push("aaa"); 二元配列  qTemp.push( qRec[ i ] );
    [  shift     ]   配列の先頭の要素を削除します。 qPre.shift( );  qPre[ ] の先頭要素が削除される。
                          二元配列   qDummy=qRec.shift( ); qRec[0] にqRec[1] データが繰り上がる。
   [  pop      ]   配列の最後の要素を削除します。 qRec.pop( ); qRec[ last ] が削除される。
   [  slice    ]   0 から数えて、start 番目〜 end - 1 番目までの要素を抜き出した配列を返します。
                        end を省略した場合は最後までの要素を返します。array は変化しません。
                                                 二元配列   qDummy=qRec.slice( 3, 5 );
  二元配列を空にする

    JavaScript には、配列を空にするメソッドはないので、次のように関数を作成して空にする。
          qRec.length =0; とすると、配列は空となるが、繰り返すとエラーとなる。

     delArray( qRec);

           //配列を空にする   (配列の先頭行を配列要素数だけ繰り返す)
     function delArray(sqs){
        var n = sqs.length;
          var qDummy;
        for( var i=0; i<n; i++){
                         qDummy=sqs.shift();
                 }
            }  
  
 二元配列のデータをコピーする
 
    二元配列 qRec[ ][ ] で次の式でコピーができるが、
        qTenp = qRec;    alert( qTemp{ 2] [ 3] );  などでデータのセットが確認できる。
     これは名前を変えられるのみで、qRec[ ][ ] の要素を削除すると、qTemp{ } [ ] の要素も削除される。

     真に、二元配列のデータをコピーするには、次のように関数を作ってデータをセットする。
     この方式を使えば、繰り返し配列に新しいデータをセットできる。

     transArray(qTemp, qRec);

     //配列のデータをsqsA[]からsqsB[]に移す
           function transArray(sqsA, sqsB){
                 if ( sqsB.length >0 ) {  delArray(sqsB); } //sqsBを空にする
                 for( var i=0; i<sqsA.length; i++) {
                       sqsB.push(sqsA[i]);
                 }
                 // delArray(sqsA);  //必要であれば、sqsAを空にする
           }
 
#D
 VBScriptでの配列の記述法
  
 [一次配列の宣言と初期値の設定] 
Dim qS( 4)        //qS名で0〜4の要素をもつ一次配列を宣言
qS( 0) = 21   //VBScriptの配列はqS( n)と要素数をいれて、データの記憶域をあらかじめ
qS( 1) = 22      //確保する形になっている。
qS( 2) = 23
qS( 3) = 24

Dim qTest                               //変数を定義して置き
qTest = Array(10,20,30)          // Array( ) で値をセットする
[一次配列へSplit関数で文字列からデータをセットする]  
Dim strVal, sAns
Dim qS
strVal = "11,12,13,14,15"
qS = Split(strVal,",")  //カンマで区切る
sAns =""
for i=0 to 3
 sAns = sAns & qS(i) & vbCrLf
next
msgbox sAns
                    二次配列へSplitする方策があれば便利ですが、現在までには見出せません。

[二次配列の宣言と初期値の設定]
 Dim qA(3,3)
 qA(0,0)=21: qA(0,1)=35: qA(0,2)=41: qA(0,3)=57
 qA(1,0)=22: qA(1,1)=34: qA(1,2)=44: qA(1,3)=56
 qA(2,0)=23: qA(2,1)=33: qA(2,2)=42: qA(2,3)=55
 qA(3,0)=24: qA(3,1)=32: qA(3,2)=43: qA(3,3)=54
                     VBScript では基本的には、実行行は1行で記述し、行末には;などを付けない。
         しかし行末に:(コロン)を付けると複文として記述できる。上のようにするとテーブル型で見やすい。

 [二次配列の再宣言(動的配列、ReDim)の設定」 (正規にはRemステートメントという)
Dim qX( )
Dim nR=2: Dim nC=3
ReDim qX(nR , nC)
qX(0,0)=21: qX(0,1)=35: qX(0,2)=41: qX(0,3)=57
qX(1,0)=22: qX(1,1)=34: qX(1,2)=44: qX(1,3)=56
         ReDimは先にDimをしておかないと実行できない。この場合でもあらかじめ要素数を確定する必要がある。
         要素数の設定は、変数でもできる。
                    このようにVBScriptの配列は固定サイズの配列と動的配列の2種類が存在する。
         また、VBScriptでは変数にも配列をセットできるので、一次配列にそれぞれ配列を代入して二次配列データと
         することができる。

[ CSVデータを二次配列にセットする]
                  テストCSVデータ
Hinnshumei,Kana,Sansho
相合傘,あいあいがさ,"紅色の小輪"
愛染,あいせん,"白地紅縦絞の大輪"
愛祖の里,あいそのさと,"紅の中輪"

Dim qA()  '配列の仮宣言
Dim lines, i
Dim objFS, strm

Set objFS = CreateObject("Scripting.FileSystemObject")
' ファイルを読み込む
Set strm = objFS.OpenTextFile("testA.csv")
Dim sA
sA = strm.ReadAll '全文を一度に読み込む
' 末尾に改行がついていたら削除。空の配列要素が最後に追加されるのを防ぐ
If InStrRev(sA, vbCrLf) = Len(sA) - Len(vbCrLf) + 1 Then
    sA = Left(sA, Len(sA) - Len(vbCrLf))
End If
' 改行コードで分割
lines = Split(sA, vbCrLf)
strm.Close

Dim ubqA
ubqA = UBound(lines)
msgbox ubQA
ReDim qA(ubqA)
For i = 0 To UBound(qA)
   qA( i )=Split(lines( i ), ",") '一次配列にそれぞれ二次配列をセット
Next
msgbox qA(2)(2)

        CSVの全文を読み取り、これを改行コードでsplitしてlines配列にまずセットします。UBound(lines)で行数に相当する
        レコード数が得られますので、これでqAをReDim宣言します。
        一次配列qAの各要素にlines要素をカンマでsplitして配列としてセットします。
        こうして出来た二次配列のデータもqA(2)(2)の形で参照できます。

[Dictionaryオブジェクトを用いて二元配列にデータをセット]
dim Stream(3),line     
Stream(0)="A0,20,B0,40,C0"     //文字列を配列にセット
Stream(1)="A1,21,B1,41,C1"
Stream(2)="A2,22,B2,42,C2"
Stream(3)="A3,23,B2,43,C2"
Set dic = CreateObject("Scripting.Dictionary") //Dictionaryオブジェクトを作成
for i=0 to 3
   line = stream( i )
   Call dic.Add(dic.Count, split(line, ","))  //カンマ区切りで配列としてセット
next
Dim qA()                     '動的配列を宣言
ReDim qA(dic.Count-1, 1) '配列数は"dic.Count-1"
For i=0 to dic.Count -1   
   qA(i,0) =dic.Item(i)(0)
   qA(i,1) =dic.Item(i)(4)
Next
for i=0 to Ubound(qA,1)
   msgbox qA(i,0) & "::" & qA(i,1)
next
        DictionaryオブジェクトはWSHの組み込みオブジェクトの1つです。
         VBScriptの配列は要素数を先に宣言しないと使えないので、行数が可変のCSVファイルのデータを読めません。
                  そのために、Dictionary配列に読み込んだのち、行要素数を取得して後に、通常の配列にデータセットします。
                  ここでは、dic.Item( )( )から、列0と列4のデータのみを切り分けて新しい配列を作成しています。   
        このコードでは、外部ファイルを1行づつ読みとった後に、二元配列にセットする処理のデモです。
        外部ファイルを1行づつ読みとったデータの代わりに、Stream( )配列の文字列データでテストしている。
                  なお、dic配列は本来は”キー:値”の形ですが、ここでは"値"部分に配列をセットしています。
                  これはJavaScriptの二元配列が「配列の配列」であるのと同じ仕様です。

                 なお、VBScriptの配列については、次のページの記述が参考になります。
                      「配列再考」        http://www012.upp.so-net.ne.jp/scotchegg/VBScript/Array.htm

#E
 JavaScriptの二元配列のsort VBScriptの二元配列のクイックソート

   JavaScriptには配列のソートにsortメソッドがありますが、多くの例示は一元配列のみです。
   VBScriptには配列のソートメソッドなどがありませんので、自分で作成する必要があります。
   こちらも二元配列の例示はありませんので、すぐに使えるように記述します。

 [JavaScriptの二元配列のソート]

<html>
<head>
<title>二元配列のデータをソートする(バブルソート/交換法)</title>
<script language="JavaScript"><!--
//http://stabucky.com/wp/archives/227
//http://ma-bank.com/item/752  多元配列ソート

var qRec=new Array();
csv="1,fa,200; 2,ab,100; 3,cs,400; 4,d,350; 5,af,50";

lines=csv.split(";");
for(i=0;i<lines.length;i++){
    qRec[i]=lines[i].split(",");
}

document.write("<p>【 二元配列を列でソートする。】</p>");
document.write("<p>sortメソッドでは列に数値と文字列が混合では不可</p>");
document.write("<p>そのまま表示</p>");
document.write(maketable(qRec));
document.write("<p>3列目でソート(0から数えて2)</p>");
document.write(maketable(xsortS(qRec,2,1)));
document.write("<p>1列目で逆ソート</p>");
document.write(maketable(xsortS(qRec,0,-1)));
document.write("<p>2列目の文字でソート</p>");
document.write(maketable(xsortS(qRec,1,1)));

//document.write(qRec.toString());

function maketable(sqs){
    //表形式で表示
    //sqs:二次元配列
    var ret;
    ret="<table border=1>";
    for(i=0;i<sqs.length;i++){
        ret+="<tr>";
        for(j=0;j<sqs[i].length;j++){
            ret+="<td>"+sqs[i][j]+"</td>";
        }
    ret+="</tr>";
    }
    ret+="</table>";
    return(ret);
}

function xsortS(sqs,col,order){
    //二次元配列のソート:文字列もソート
    //col:並べ替えの対象となる列
    //order:1=昇順、-1=降順
    sqs.sort(function(a,b){
  if(isNaN(a[col])) {
        return (a[col] > b[col]) ? 1*order : -1*order;
  
     }else {
         return( (a[col] - b[col]) * order);
     }
 });
    return(sqs);
}
// --></script>
</head>
<body>
  
</body>
</html>

 
  [VBScriptの二元配列のクイックソート]

Option Explicit
 ' 【 qsortBinaryArray.vbs 】 - ニ元配列のクイックソート
 '    http://tuka.s12.xrea.com/index.xcg?p=VBS#p16
 '      (一元配列のクイックソート)を変更
 '    ソート行範囲を指定できるので、CSVなど最初行が項目名の
 '    二元配列のソートに便利である。
 '
 Dim sB, sE, sF
 Dim qA(4,3)
 qA(0,0)=" A": qA(0,1)=" B": qA(0,2)=" C": qA(0,3)=" D"
 qA(1,0)=22: qA(1,1)=34: qA(1,2)=45: qA(1,3)=56
 qA(2,0)=23: qA(2,1)=33: qA(2,2)=43: qA(2,3)=55
 qA(3,0)=24: qA(3,1)=32: qA(3,2)=42: qA(3,3)=54
 qA(4,0)=25: qA(4,1)=31: qA(4,2)=44: qA(4,3)=53

 sB =dispArray(qA)
 '行0を除いた範囲で列1で昇順にソート
 Call quicksort(qA, 1, 1, UBound(qA), "As")
 sE =dispArray(qA)
 '行0を除いた範囲で列2で降順にソート
 Call quicksort(qA, 2, 1, UBound(qA), "Des")
 sF =dispArray(qA)
 msgbox sB & vbCrlf & sE & vbCrlf & sF

 ' クイックソート本体(昇順降順)(再帰)
 Sub quicksort(sqa, col, first, last, sort)
  ' sqa:配列名  col:ソート対象0から始まる列番号
  ' first:ソート行範囲最初行番号  last:ソート行範囲最終行番号
  ' sort:昇・降順別 "As"/"Des"と文字列を記述する。
  '
     Dim point, f, l, m, wk
     point = sqa(first,col)
     f = first: l = last
 
     Do
        If sort = "As" then
   While sqa(f,col) < point: f = f + 1: Wend
         While sqa(l,col) > point: l = l - 1: Wend
        Else
   While sqa(f,col) > point: f = f + 1: Wend
         While sqa(l,col) < point: l = l - 1: Wend
  End if
  If f >= l Then Exit Do
         'tmp = sqa(f): sqa(f) = sqa(l): sqa(l) = tmp
        For m = 0 to UBound(sqa,2)
   wk = sqa(f,m): sqa(f, m) = sqa(l, m): sqa(l, m) = wk
  Next
  f = f + 1: l = l - 1
     Loop
     If first < f - 1 Then quicksort sqa, col, first, f - 1, sort
     If l + 1 < last  Then quicksort sqa, col, l + 1, last, sort
 End Sub

 ' 配列内容を表示する
 Function dispArray(qD)
 Dim i, j, sA
  For i = 0 To UBound(qD, 1)
     For j = 0 To UBound(qD, 2)
   sA = sA + CStr(qD(i, j)) & ", "
     Next
  sA = Left(sA, Len(sA)-2) '末尾の,を削除
  sA = sA & vbCrLf
 Next
 sA = sA & vbCrLf
 dispArray =sA
 End Function



 CSVファイルの編集プログラム

二元配列を用いた操作の実際例として、具体的なプログラムを作成した例でプログラム構成とその処理の速度を検討しましたので紹介します。

 camSumシステムはhtmlによる洋種ツバキの検索機能をもつ品種画像表示プログラムです。このプログラムは、camSum3.csvという管理データCSVにより、品種名、品種画像、品種参照文を表示します。

 管理データCSVのcamSum3.csv は下のようなデータです。

no,name,caption,img,ref,group,source,folder,sizeM,fformM,by,year
・・・・・
23,MarkChason,M,MarkChason_Cw3.jpg,MarkChason.txt,jap,camWeb,camWeb,L,S,Gilley,1977
24,MarkEleven,M,MarkEleven_acs.jpg,MarkEleven.txt,jap,AcsEncy,AcsEncH_M,L,S,Mandarich. J.,1969
25,MaryAgnesPatin,M,MaryAgnesPatin_Ni.jpg,MaryAgnesPatin.txt,jap,Nisi,NisiColl,L,R,Patin. T.C. ,1961
・・・・
 
  camSum3.csv のデータは、左から「レコード番号」、「品種名」、「英頭文字」、「画像ファイル名」、「品種参照テキスト名」、「品種の区分」、「画像グループ」、「画像フォルダー名」、「花のサイズ」、「花型分類」、「育成年」、「育成者」からなります。
 camSum3.csv は11項目で 3151レコードのやや大きなデータです。
 このデータファイルから、inndexファイルとして、no項目とyear項目データのみを切り出し、これを昇順、降順して、それぞれcamSum3_As.csv と camSum3_As.csvに出力・作成するします。
 さらに、year項目データは年代不明の品種は、ソート処理のためにyear=10としてありますが、昇順のcamSum3_As.csv では year =3000として、ソートします。

SortCsv.jpg
#F
 処理方法の選択 (CSVファイルの読み書きの概要)

 camSumシステムの表示部分は、html_JavaScript で記述されていますが、上のcamSum3.csv はhtmlの外部データファイルですので、JavaScript(jQuery)、VBScript を使用する範囲では調査した結果では次の方法が想定できます。
       1)  html内でJavaScript(jQuery)でAjaxで読み込み処理する方法
       2)  html内でVBScript で読み込み処理する方法
       3)  WSH_VBScriptで読み込み処理する方法
 
 その他に類似するWSH_JScriptの系がありますが、JScriptはやや一般的でないので、ここでは検討していません。
 
 2) と 3) は、VBScript をhtml内に記述するか、vbs として単独で実行できるコードとするかの違いがありますが、主要な処理コードは類似しています。前者では、JavaScript を主体とし、処理関数をVBScript記述する方法が一般的ですので、JavaScriptの関数、メソッドなどが利用できます。

 3) のWSH_VBScriptでは、csvファイルの読み込みには、
    3a)  Scripting.FileSystemObject(FSO)を利用する方式
    3b)  ADODB.Connection(ADO)を使用する方法
      があげられます。
 
 各処理方法の具体的な手順 
  
 上の全体的な処理方式系列について、具体的に使用するツール・関数をWeb/テキストで調査し、利用できるかを検討して手順を設定すると、次のようになります。

 1) html_JavaScript(jQuery)でAjaxルート
   jQueryの$get$csv でcvsファイルを読み込み、JavaScriptの二元配列 qRec[ ][ ]にデータをセットする。
   JavaScriptのsortメソッドでソートする。 (二元配列のソートには JavaScriptのsort( )を利用する)
   JavaScriptのtoString でcsv出力用の文字列を作成する。
   VBScript のFSOを使い、文字列をcsvファイルに出力する。
 
  2) html_vbs_FSO_Array_Xsort ルート
   VBScript のFSOを使い、csvファイルを読み込み、qRec[ ][ ]にデータをセット
   qRec[ ][ ] を昇順用 qRecY[ ][ ] にno項とyear項を書き出す。
   qRecY[ ][ ] を xsortする。csv用文字列を作成し、FSOで書き出す。
   qRec[ ][ ] を降順用 qRecX[ ][ ] にno項とyear項を書き出す。
   qRecX[ ][ ] を xsortする。csv用文字列を作成し、FSOで書き出す。

  3a) WSH_vbs_FSO_Array_quicksort ルート
   FSOでcvsファイルを読み、dic.Item[ ][ ] の全データをセット
   dic.Item[ ][ ] からno,year値を qA( n, 0), qA( n, 1) にセット
       qA( n, 0), qA( n, 1) をquicksortDes( )関数で降順ソートする
   降順ソートしたqA( n, 0), qA( n, 1) を文字列に変換する
   qA( n, 0), qA( n, 1) のyear =10 を3000をセット                                            
   qA( n, 0), qA( n, 1) をquicksortAs( )する               
      昇順ソートしたqA( n, 0), qA( n, 1) を文字列に変換する   
   FSOで、sSortDesをFSO_Dic_Array_Des.csvに、sSortAsをFSO_Dic_Array_As.csvに出力 
   ***************************
     VBScriptの二元配列はqA(max,1) はデータ入力前にmax値で宣言しないと利用できない。
    そのために、dic.Item[ ][ ] にセットしたのちに、no,year値を qA( n, 0), qA( n, 1) にセットする必要がある。
     quicksortDes( )関数:VBScriptにはソート関数がないので、自分で作成する必要がある。
    多くのソートのコード例があるが、これらは一元配列用であるので、二元配列用に変更を検討する必要がある。
       ***************************

 3b) WSH_vbs_ADODB_Array ルート
   csvファイルをADODBのseelect文でyear項目で降順ソートで読み、レコードoRsでnoとyearのデータをsDesに集める
   昇順用に、FSOでcsvを読み込み、year=10をyear=3000に置換し、書き戻す。
   csvファイルをADODBのseelect文でyear項目で昇順ソートで読み、レコードoRsでnoとyearのデータをsAsに集める。
   FSOでsDes をcam_Des.csvに、sAsをcam_As.csv に書き出す。
       ***************************
     ADODBではcvsファイルはselect文でソートしながら、レコードoRs としてセットされる。
     しかし、このoRs は更新できない。そのために、FSOの置換関数で year=10 を 3000に置換してから、selectを実行する。
     oRsを直接に出力用文字列とするメソッドはない。 FSOで文字列を合成してファイル出力している。
       ***************************
#G
 各ソート処理の処理速度 

 上の方式で作成したソートプログラムの処理速度を比較・検討した。

 [ html_jQ_$Get$csv_Array_Xsort]   (vbsGet_Array_Xsort.html)
      csvを$get/$csvし、データ10を300に変更、qSortAs[ ][ ]にセット                      :469ms
       qSortAs[ ][ ]をxsortする                                                     :640ms
       qSortAs[ ][ ]をtoStringで文字列に変換する                                          :9016ms
       ( 文字列に変換処理で時間が掛かるので以後の検討を省略 )

[ html_vbs_FSO_Array_Xsort ]  (JvS_vbsで読み配列にセットXsortする.html)
      FSOでcsvを読み、qRec[ ][ ]にセット、qRecY[ ][ ]にデータを切り出す。                  :250ms
      QRecY[ ][ ] を昇順にxsortする。                                                                   :172ms  
      QRecY[ ][ ] をcsv文字列に書き出し、FSOでcamSum_sub_As.csvに書き出す。       :8219ms
      qRec[ ][ ]にから、qRecX[ ][ ]にデータを切り出す。降順にxsortする。          : 187ms
   QRecX[ ][ ] をcsv文字列に書き出し、FSOでcamSum_sub_Des.csvに書き出す。     :10531ms
                                                                                                ( トータル :19359ms)
      (文字列にno項データとyear項データを結合する処理が8秒強かかる。)

[ WSHVBS_FSO_Dic_Array_qsort ]  (vbs_FSO_Dic_Array.vbs )
      FSOでcsvを読み、dic.Itemにセット、                                                               : 62ms
      dic.Item[ i ][ j ] をqA( n, 0), qA( n, 1) にno,year値をセット                                    : 31ms
      qA( n, 0), qA( n, 1)  をquicksortDes( )する                                                            : 78ms
      降順ソートしたqA( n, 0), qA( n, 1)  を文字列に変換する                                           :156ms
      qA( n, 0), qA( n, 1)  のyear =10 を3000をセット                                                      :0ms
      qA( n, 0), qA( n, 1)  をquicksortAs( )する                                                              :250ms          
      昇順ソートしたqA( n, 0), qA( n, 1)  を文字列に変換する                                           :187ms
   FSOで、sSortDesをFSO_Dic_Array_Des.csvに、sSortAsをFSO_Dic_Array_As.csvに出力  :  62ms
                                                                                                          (トータル  :750ms )
[ WSHVBS_ADODB_Array ]  (csvをSqlでソート項目分離する.vbs)
       ADODBのseelect文で全項目を降順ソートし、oRsでnoとyearのデータをsDesに集める。 :328ms
    FileSystemObjectでcsvを読み込み、year=10をyear=3000に置換し、書き戻す。          : 68ms 68
    ADODBのseelect文で全項目を昇順ソートし、oRsでnoとyearのデータをsAsに集める。  :244ms  244
       sDes をcam_Des.csvに、sAsをcam_As.csv に書き出す。                                           : 63ms  63
                                                                                                            (トータル  :703ms )
     (文字列にno項データとyear項データを結合する処理が速い)

   html内でjQueryの$get#csvでcsvファイルを読み、JavaScriptの二元配列にセットする処理と、VBScriptのFSOで読み、
   同様にJavaScriptの二元配列にセットする処理はほぼ同じ処理時間で問題は少ない。
   しかし、html内記述では、JavaScriptのtoStringメソッドと通常にループ配列値をcvs出力文字列を作成する処理は、8〜9
   秒が掛かり、これが全体の処理速度を大きくしています。

   WSH_vbs系では、FSOでcsvファイルを読み、dic.Itmにセットする処理の速度は速い。
   dicItem( i )( j ) から、VBScriptの二元配列 qA( n, m)にセットするのも速い。
   qA( n, m) のquicksort は156ms, 250ms で使用できる速度である。
   qA( n, m) をcsv形式の文字列に変換する処理は、156ms, 187ms と比較的に速い。

   WSH_vbs系で、ADODBでは、select文で昇順・降順のソート、項目切り出しなどができる。
   VBScriptの二元配列にセットする速度も速いので、ここでデータの更新も可能である。
   (上の例では、no項目とyear項目をoRsから文字列に変換している。)
   

     

上の検討での処理速度の速かったWSH-VBScriptの2つのコードを紹介します。


  WSH-VBScript FSOのRW・ソート (Csvファイルを読み込み、部分項目のレコードをソートして出力する)

 FSOでの入出力でCsvファイルの部分切り出しとソートをします。dic.Item( n)(m)にセットしてから、VBScriptの二元配列にセットする点がポイントです。ソートは上記のquicksort( ) をつかっています。
 WSH_VBScript1では文字列の結合処理が比較的に速いのが特徴です。

'WSH_VBScript記述
'CSVファイルをFSOで読み込み、dic.Item[][]にセットする
'dic.Item[][]からqA( , 1)にno,year値をセット、同時にyear=10を3000に置き換え
'CSV出力用の文字列を作成し、FSOでファイルに出力する。
Dim oRs, a, b, c, d, e, f, g, h, i, j, sPre, sPostSort
Const adInteger = 3
Const adDate = 7
Const adVarChar = 200

a=timer()
'csvファイルデータを読む
Const ForReading = 1
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oTF = oFSO.OpenTextFile("camSum3_sub.csv", ForReading) 'camSum3_sub.csv
Dim dic
Dim line

Set dic = CreateObject("Scripting.Dictionary")
Do until oTF.AtEndOfStream
 line = oTF.ReadLine
 Call dic.Add(dic.Count, split(line, ","))
Loop
'msgbox dic.Count
b =timer()  ' 0.265
'qA( ,1)配列にno,year値をセット
Dim qA() '動的配列を宣言
ReDim qA(dic.Count -2, 1) '配列数は"dic.Count -2"
c =timer()
For i=1 To dic.Count-1 '0は読まない
   qA(i-1,0) =dic.Item(i)(0)
   qA(i-1,1) =dic.Item(i)(11)
Next
d =timer()  '全フィールドセット:0.265 2フィールド:0.0468 (0.0428)
'msgbox dic.count & " qA =" & UBound(qA, 1)
'**** 明示的なオブジェクト開放を必ず行え。ガーベジにたよるな
dic.RemoveAll
Set dic = Nothing
oTF.close
set oFSO = Nothing
'降順にソート
'Call shellSort(qA, 1, 1)
Call quicksortDes(qA, 1, 0, UBound(qA))
e =timer()
sSortDes =dispArray(qA)
f =timer()
'year =10を3000に置き換える
For i=0 to UBound(qA,1)
 if qA(i,1) = 10 then qA(i,1) = "3000"  '文字型でないと不可
Next

g =timer()
'昇順にソート
'Call shellSort(qA, 1, 0)
Call quicksortAs(qA, 1, 0, UBound(qA))
h =timer()
sSortAs =dispArray(qA)
i =timer()
'sSortAsとsSortDesの書き出し
Set Fso = CreateObject("Scripting.FileSystemObject")
With Fso.OpenTextFile("FSO_Dic_Array_As.csv", 2, True)
     .Write sSortAs
     .Close
End With
With Fso.OpenTextFile("FSO_Dic_Array_Des.csv", 2, True)
     .Write sSortDes
     .Close
End With
Set Fso=Nothing
j =timer()
 msgbox "b =" & (b-a) & "  c =" & (c-b) & "  d =" & (d-c) & "  e =" & (e-d) & "  f =" & (f-e) & vbCrLf & "  g =" & (g-f) & " h =" & (h-g) & " i =" & (i-h) & " j =" & (j-i)
 
 msgbox "all =" & (j-a)
 WScript.Quit

'二元配列のShell sort
Sub shellSort(sqa, col, order)
    'sQa:配列名 col:0から始まる列番号 order=0:昇順,1:降順
 'sSet = "[Array " & "sqa" &", " & CStr(col) &", " & CStr(order) & "]" & vbCrLf & vbCrLf
 Dim wk, i, j, k, m
 Dim n
 n = UBound(sqa)
 k = n \ 2
 Do While (k > 0) 'シェルソート
  For i = 0 To n - k
   j = i
   Do While (j >= 0)
    If order = 0 then
     If sqa(j, col) > sqa(j + k, col) Then
      For m = 0 to UBound(sqa,2)
       wk = sqa(j,m): sqa(j, m) = sqa(j + k, m): sqa(j + k, m) = wk
      Next
      j = j - k
     Else
      Exit Do
     End If
    Else
      If sqa(j, col) < sqa(j + k, col) Then
      For m = 0 to UBound(sqa,2)
       wk = sqa(j,m): sqa(j, m) = sqa(j + k, m): sqa(j + k, m) = wk
      Next
      j = j - k
     Else
      Exit Do
     End If
    End If
   Loop
  Next
  k = k \ 2
 Loop
 End Sub

' 配列内容を表示する
 Function dispArray(qD)
 Dim i, j, sA
  For i = 0 To UBound(qD, 1)
     For j = 0 To UBound(qD, 2)
   sA = sA + CStr(qD(i, j)) & ", "
     Next
  sA = Left(sA, Len(sA)-2) '末尾の,を削除
  sA = sA & vbCrLf
 Next
 sA = sA & vbCrLf
 dispArray =sA
 End Function

' クイックソート本体昇順(再帰)
 Sub quicksortAs(sqa, col, first, last)
     Dim point, f, l, m, wk
 
     point = sqa(first,col)
     f = first: l = last
     Do
        While sqa(f,col) < point: f = f + 1: Wend
        While sqa(l,col) > point: l = l - 1: Wend
        If f >= l Then Exit Do
         'tmp = sqa(f): sqa(f) = sqa(l): sqa(l) = tmp
        For m = 0 to UBound(sqa,2)
   wk = sqa(f,m): sqa(f, m) = sqa(l, m): sqa(l, m) = wk
  Next
  f = f + 1: l = l - 1
     Loop
     If first < f - 1 Then quicksortAs sqa, col, first, f - 1
     If l + 1 < last  Then quicksortAs sqa, col, l + 1, last
 End Sub
 
 ' クイックソート本体降順(再帰)
 Sub quicksortDes(sqa, col, first, last)
     Dim point, f, l, m, wk
     point = sqa(first,col)
     f = first: l = last
     Do
        While sqa(f,col) > point: f = f + 1: Wend
        While sqa(l,col) < point: l = l - 1: Wend
        If f >= l Then Exit Do
         'tmp = sqa(f): sqa(f) = sqa(l): sqa(l) = tmp
        For m = 0 to UBound(sqa,2)
   wk = sqa(f,m): sqa(f, m) = sqa(l, m): sqa(l, m) = wk
  Next
  f = f + 1: l = l - 1
     Loop
     If first < f - 1 Then quicksortDes sqa, col, first, f - 1
     If l + 1 < last  Then quicksortDes sqa, col, l + 1, last
 End Sub

  
#I
  WSH-VBScript  ADODBでCsvファイルを読み込み、部分項目のレコードをソートして出力する

 WSH-VBScript では、ADODBでも外部ファイルを読み書きができます。Csvファイルを読み取るとSelect文でソートができ、レコードセットにデータがセットされます。レコードセットの更新は、Csvファイルの読み取りでは許されていませんが、VBScriptの配列へのデータ移行は速くできます。

Option Explicit
'http://www.happy2-island.com/vbs/cafe02/capter00803.shtml
Dim objADO
Dim oRS
dim a,b,c,d,e,f,t, sA, sBa, sBb, sC, sAs, sDes,i
dim myFolder

a = Timer()
myFolder =replace(WScript.ScriptFullName,"\" &WScript.ScriptName,"")
'ADOオブジェクトを作成します
Set objADO = CreateObject("ADODB.Connection")

'ADOを使いCSVファイルを扱う準備(オープン)を行います
objADO.Open "Driver={Microsoft Text Driver (*.txt; *.csv)};DBQ=" & myFolder &";ReadOnly=1"

'降順のcam_Des.csvのデータ作成
Set oRS = objADO.Execute("select * from camSum3_sub.csv order by year desc",1)
sDes=""
Do Until oRS.Eof = True
    sDes = sDes & oRS("no") & "," & oRS("year") & vbCrLf
 'カーソルを次の行へ
    oRS.MoveNext
Loop
'レコードセットをクローズします
oRS.Close
b = Timer()

'昇順のcam_As.csvのデータ作成
Dim Fso, oF
'先にcamSum3_sub.csvのyear =10 を=3000に置換する
Set Fso = CreateObject("Scripting.FileSystemObject")
'intNum=InStrRev(location.pathname,"/",-1)
'strPath=Mid(Left(location.pathname,intNum),2)
Set oF = Fso.OpenTextFile("camSum3_sub.csv", 1, False) '"AAA.txt"
sA = oF.ReadAll
oF.Close
sBa = ",10" & VbCrLf
sBb = ",3000" & VbCrLf
sC = Replace(sA, sBa, sBb)
With fso.OpenTextFile("camSum3_sub.csv", 2)
     .Write sC
     .Close
End With
Set fso=Nothing
c = Timer()

Set oRS = objADO.Execute("select * from camSum3_sub.csv order by year ",1)
sAs=""
Do Until oRS.Eof = True
    sAs = sAs & oRS("no") & "," & oRS("year") & vbCrLf
 'カーソルを次の行へ
    oRS.MoveNext
Loop
'レコードセットをクローズします
oRS.Close
d = Timer()

'ADOオブジェクトをクローズします
objADO.Close
'オブジェクトの破棄
Set oRS = Nothing
Set objADO = Nothing

'sAsとsDesの書き出し
Set Fso = CreateObject("Scripting.FileSystemObject")
With fso.OpenTextFile("cam_As.csv", 2, True)
     .Write sAs
     .Close
End With
With fso.OpenTextFile("cam_Des.csv", 2, True)
     .Write sDes
     .Close
End With
Set fso=Nothing
e = Timer()
msgbox "b= " &(b-a) & " c= " &(c-a) & " d= " &(d-a)& " e= " &(e-a)


#J
  WSH-VBScript  ADODBでCsvファイルを読み、指定項目を編集する

WSH-VBScript でADODBを使用すると、CSVファイルから、Sql で項目選択、指定項目でのソートしたレコードセットがえられます。
 調べると、"oADO.CursorLocation = 3" とすると、RecordCountでレコード数が取得できることがわかりました。これでVBScriptの配列をReDimできますので、レコードデータをVBScriptの配列にセットできることが分かりました。この処理をfunctionとしました。
 また、setFildsData(qA,"$11", 10, "$11", 3000)として、フィールド11=10の場合、フィールド11=3000とするような簡単なデータ更新のfunctionを作りました。
 WSH-VBScript でADODBのシステムが現在では処理速度が最も速いと思われます。


Option Explicit
'【 ADODBによるCsvファイル編集コード ADODBreadCsv.vbs 】
'   [ADDB_Sqlでソート項目分離する.vbs]を変更する
'   setCSVtoArray(sSql):sSqlのselect文で対象csvを読み込みソートを設定する
'   setFildsData(qA,"$11", 10, "$11", 3000)
'        : qA配列のfield(11)=10のレコードでfield(11)=3000 にデータを更新する。
Dim oADO
Dim oRS
dim a,b,c,d,e,f,t, sA, sB, sC, i, j
dim myFolder
'myFolder =replace(WScript.ScriptFullName,"\" &WScript.ScriptName,"")
a = Timer()
dim qA, qB
sA = "select * from camTest.csv order by year desc"
qA = setCSVtoArray(sA)
b = Timer()'no=0.281 desc=0.381

msgbox "Time =" & (b-a)
qB = setFildsData(qA,"$11", 10, "$11", 3000)
sB=""
for i=0 to UBound(qB,1)
 sB=sB & CStr(qB(i,0)) & "," & CStr(qB(i,11)) & VbCrLf
next
msgbox sB
WScript.Quit

function setCSVtoArray(sSql)
 'sSql文を実行し、配列sTemp(m,n)にセットし戻値とする
 dim sTemp
 'ADOオブジェクトを作成します
 Set oADO = CreateObject("ADODB.Connection")
 'ADOを使いCSVファイルを扱う準備(オープン)を行います
 oADO.Open "Driver={Microsoft Text Driver (*.txt; *.csv)};DBQ=" & myFolder &";ReadOnly=1"
 oADO.CursorLocation = 3 'クライアントサイドカーソルに変更 これでoRs.RecordCountが取得できる。
 Set oRS = oADO.Execute(sSql,1)
 Redim sTemp(oRs.RecordCount -1, oRs.Fields.Count -1)
    oRs.MoveFirst
 for i=0 to oRs.RecordCount -1
     for j=0 to oRs.Fields.Count -1
         sTemp(i,j) = oRS(j)
     next
     oRS.MoveNext
 next
 'レコードセットをクローズします
 oRS.Close
 oADO.Close
 'オブジェクトの破棄
 Set oRS = Nothing
 Set oADO = Nothing
 setCSVtoArray =sTemp
End function

function setFildsData(qName, fNoA, fValueA, fNoB, fValueB)
 'qName:配列名
    'fNoA:$11などフィールド名A  fValueA:field(11) = fValueA の行の
 'fNoB:$11などフィールド名B  fValueB:field(11) = fValueB に更新する
 dim qN
 qN = qName
 fNoA = Mid(fNoA,2)
  fNoB = Mid(fNoB,2)
 for i=0 to UBound(qN,1)
     if qN(i,fNoA) = fValueA then qN(i,fNoB) = fValueB
 next
 setFildsData = qN
end function


#K
  html用のFSO読み書きなどの関数セット
 
      html を作成するたびに、FSOの読み方・書き方のコードを見直すのは面倒ですので、FSOの関数セットをつくりました。
             すべて、同じフォルダーのファイル読み取り、書き出し、新設、削除します。

<html>
<head>
<script type="text/javascript"><!--
//【 FSO_RW.html 】
// FSOの読み書きの関数セット
onload =function init() {
 //関数が下に記述されているので、onload =function init()内に記述する
 var sA = readTxt("camTest.csv");
 alert(sA);
 var sF = "newCamTest.csv";
 makeNewText(sF);
 writeText(sA, sF, 2 );
 //if(existFile(sF)) { deleteFile(sF) }
 } 
//--></script>
<script language= "VBScript">
 '参照:http://www.happy2-island.com/vbs/cafe02/capter00211.shtml
 'すべての処理で同じフォルダーのファイルを読み、新設し、書き出す。
 'ファイルを読む
  Function readTxt(sFile)
      'msgbox sF
      Set fso = CreateObject("Scripting.FileSystemObject")
      intNum=InStrRev(location.pathname,"/",-1)
      strPath=Mid(Left(location.pathname,intNum),2)
      Const ForReading = 1,ForWriting = 2,ForAppending = 8
      Set objFile = Fso.OpenTextFile(strPath & sFile, 1)
      sA = objFile.ReadAll
      'msgbox sA
      objFile.Close
      Set fso=Nothing
      readTxt =sA
  End Function
  'ファイルに書き込む
  Function writeText(sA, sFile, constNo )
      Set fso = CreateObject("Scripting.FileSystemObject")
      intNum=InStrRev(location.pathname,"/",-1)
      strPath=Mid(Left(location.pathname,intNum),2)
      'msgbox "書き込む " & strPath & sFile
  
      Const ForReading = 1, ForWriting = 2, ForAppending = 8
      With fso.OpenTextFile(strPath & sFile, constNo, true) //trueとするとなけらば新設する
          .Write sA
          .Close
      End With
      Set fso=Nothing
  End Function
  '新規ファイルを作成する
  Function makeNewText(sFile)
  Set fso = CreateObject("Scripting.FileSystemObject")
  intNum=InStrRev(location.pathname,"/",-1)
     strPath=Mid(Left(location.pathname,intNum),2)
  strCreateFile = fso.BuildPath(strPath,sFile)
  'msgbox strCreateFile
  fso.CreateTextFile strCreateFile
  Set fso = Nothing
  makeNewText = True
  End Function
 'sFファイルが存在するか
 Function existFile(sFile)
 Set fso = CreateObject("Scripting.FileSystemObject")
 intNum=InStrRev(location.pathname,"/",-1)
    strPath=Mid(Left(location.pathname,intNum),2)
    sA = fso.BuildPath(strPath,sFile)
    'msgbox sA
    If fso.FileExists(sA) = True Then
     existFile = 1 'true:非0
    Else
     existFile = 0 'false:0
    End If
    Set fso = Nothing
 End Function
'sFileを削除する
 Function deleteFile(sFile)
 Set fso = CreateObject("Scripting.FileSystemObject")
 intNum=InStrRev(location.pathname,"/",-1)
    strPath=Mid(Left(location.pathname,intNum),2)
    sA = fso.BuildPath(strPath,sFile)
 fso.DeleteFile sA
  Set fso = Nothing
 End Function
</script>
<style type="text/css">
</style>
</head>
<body></body></html>


#Z
  その他の関連事項のコードとメモ

  [html から外部のvbsファイルを実行する]   [ html でのカレント・ディレクトリーの取得 ]

<html><head>
<script type="text/javascript">
    //htmlからbatを実行する JScriptです。
    var sF = location.pathname;
    var intNum = sF.lastIndexOf("/");
    var sPath = sF.substring( 1, intNum+1)//2文字目から
    var WshShell = new ActiveXObject("WScript.Shell");
    WshShell.run( sPath + "ADDB_Sqlでソート項目分離する2.vbs ArgBBB");
    WshShell =null;
    //htmlから引数付きで他のhtmlを表示する
    location.href = "./Test.html?BBB"
    //location.href = "./readAppend.vbs"; //これは実行ではなく「開く」「保存」と聞かれる
</script>
</head>
<body></body></html>
                        上のコードは実際にはJScriptとしてのコードです。IEではJavaScript の宣言で、JScript の記述が可能です。
                        注意する点は、普通には .vbs プログラムを単独で実行する場合には同じフォルダーのファイルを開く場合に
                      は、ファイル名だけを記述すれば実行できますが、htmlから実行される場合には、カレント・ディレクトリーを付け
                      ないとエラーとなします。
                       上のlocation.pathnameはVBScript関数内でも使えます。

           「WshShell.run( sPath + "ADDB_Sqlでソート項目分離する2.vbs ArgBBB");」のように、vbsファイル名の後に1
          文字を置いて ArgBBB と記述すると、vbsファイルに引数が送れます。
           受けるvbsファイル側では、
             if(WScript.Arguments.count =1 ) then msgbox WScript.Arguments.Item(0) として受けることができる。

           「location.href = "./Test.html?BBB"」と記述すると、同じフォルダーのTest.html に引数付きで開けます。
           受けるhtml 側では、 
             str=location.search; (JavaScriptで記述) します。   
 
[jQueryのプラグインjquerycsv.js の注意点]

        プラグインjquerycsv.jsは、CSV文字列をデリミタ","で分けて二元配列にデータをセットします。
         $.get( dataCsvFile, function( text ) { qRec =$.csv()(text); });
       とすると、dataCsvFileのデータをqRec[ ][ ] にセットします。
        しかし、エクセルで出力したCSVファイルを処理すると、レコード数 qRec.length が実際より1つ多くなります。
        これは、CSVファイルの最後の行の改行( \r\n )をとると、実際のレコード数となります。
        CSVファイルの最終行の改行はあってもなくてもよいことになっていますので、間違いではないようです。

                  VBScript のSplit関数で処理した場合も最後の行に改行があると、実際のレコード数は1つ多くなります。
 
        下の関数setCsvToArray( ) では、最後の行の改行があっても、なくても実際のレコード数となります。

<html>
<head><title>Camellia csvCardSum</title>
<script type="text/javascript" src="subf/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="subf/jquerycsv.js"></script>
<script type="text/javascript">
var qRec      = new Array();
onload =function init() {
 var dataCsvFile = "camTest.csv";
 //$.get(dataCsvFile,function(text){ qRec =$.csv()(text); });
 $.get(dataCsvFile,function(text){ qRec = setCsvToArray(text); });
 alert("qRec.length = " + qRec.length);
 var sD="";
 for(var i=0; i<qRec.length; i++) {
    sD = sD + qRec[ i ][ 0] + ", " + qRec[ i ][ 11] + "\r\n"
 }
 alert(sD);
}
function setCsvToArray(sR) {
  var qTemp = new Array();
  var qA = sR.split(/\r\n/);
  for( var i = 0; i < qA.length; i++){
           var qB = qA[i].split(",");
           qTemp[i] = new Array();
           for( var j =0; j<qB.length; j++ ) { qTemp[ i ][ j ] =qB[ j ]; }
        }
  return( qTemp );
}
</script>
</head>
<body></body></html>

                   外部CSVファイルを処理するには、vbsなどの短いプログラムをhtmlの中から実行したり、vbs から他の
                  vbsを実行するコードが必要になります。                 
         下は、引数付きで外部実行ファイルを起動するコードです。

<html>
<head>
<title>引数付きで外部プログラムを実行する</title>
<script type="text/javascript"><!--
onload =function() {
 var sF = location.pathname; //カレントディレクトリーを知る
 var sPath = sF.substring( 1, sF.lastIndexOf("/")+1)  //2文字目から
 //vbs を引数付きで実行する
 var WshShell = new ActiveXObject("WScript.Shell");
    WshShell.run(sPath + "readArguments.vbs ArgBBB");
    WshShell =null;
    //html に引数付きで開く
 //location.href = "./Test.html?BBB"   //実行可 ?BBBも読める
 //location.href = "./readAppend.vbs"; //これは実行ではなく「開く」「保存」と聞かれる
}
//--</script>
</head>
<body>
<p>
引数付きで.vbsを実行する(VBScript)<br>
if(WScript.Arguments.count =1 ) then msgbox WScript.Arguments.Item(0)
<br><br>
</p>
<p>
location.searchで?以下の文字列を取得する(html)<br>
受けて側では<br>
str=location.search;<br><br>
</p>
<p>
【 VBScript でのWScript.Shellの記述法 】<br><br>
Dim sPath, oShell<br>
sPath =replace(WScript.ScriptFullName,"\" &WScript.ScriptName,"")<br>
Set oShell = WScript.CreateObject ("WSCript.shell")<br>
oShell.run sPath & "\" & "readArguments.vbs ArgBBB"<br>
Set oShell = Nothing<br>
</p>
</body></html>

[ ソート手法選択での留意点 ]

                    CSVデータからの配列をソートする場合に、ソート法の選択に注意が必要な場合があります。
                    グループ群別に品種名をリスト表示する場合に、各グループ内ではそれぞれアルファベット順に品種名を表示
                    したい場合があります。
                    この場合に、元の配列データを「品種名」で昇順ソートし、次いで「グループ名」でソートしますが、これには、
                    「安定したソート」を使う必要があります。
                    クイック・ソートは迅速なソートですが、「安定したソート」ではありません。

SortsResult.jpg 右の数値は、左から、バブル・ソート、シェル・ソート、クイック・ソートの結果です。

 いづれも一番上が元の二元配列のデータです。2番目が2列目でデータを昇順ソートした結果です。
 (いずれのソートでも、2列目は30〜35と昇順ソートされています。)
3番目は、2番目の配列結果をさらに、3列目で降順ソートした結果です。
 いずれのソートでも3列目のデータは45〜41と降順ソートされていますが、バブル・ソートとシェル・ソートでは、3列目が41の部分は2列目では32〜35と上の昇順ソートの順ですが、クイック・ソートでは、3列目の41部分の2列目データは34,35,32,33と昇順にはなっていません。

 結論としては、バブル・ソート、シェル・ソートでは、一度昇順ソートし、降順ソートすると、同一データ(この場合では41)の場合は、元の配列順が残り、クイック・ソートでは、同一データ部分では必ずしも元のデータ順にはなりません。
 バブル・ソート、シェル・ソートは「安定したソート」、クイック・ソートは「安定してないソート」といわれます。

[ AppPath を知る ]

VBScriptの実行ホストによって、取得方法が異なります。

HTAなら、HTA.commandLine
HTMLなら、window.location.pathname
WSHなら、
   vbsを単独で実行なら
        Set oWshShell = CreateObject("WScript.Shell") 
        appPath = oWshShell.CurrentDirectory
        Set oWshShell = nothing
   他からCall される場合には、
        WScript.ScriptFullNameとWScript.ScriptNameから取得
        myFolder =replace(WScript.ScriptFullName,"\" &WScript.ScriptName,"")
ASPなら、Request.ServerVariables("SCRIPT_NAME")、必要に応じて Server.MapPathを併用
 
[参照] WScriptオブジェクト (Wscript)  http://www.roy.hi-ho.ne.jp/mutaguchi/wsh/

[ myCookieを使う ]
         Cookie(クッキー)はhtmlに付随する簡単なデータを保存するに便利なシステムです。Webページへの訪問数の
        表示用データの保存によく使われます。 vbsプログラムやhtmlプログラムでも簡単なデータを簡単に保存するのに
        利用する解説があります。 しかし、実際には、日時データの設定が必要であったり、簡単にCokieのデータが確
        認できないなど不便な点もあります。
         それで、簡単にデータを保存できるCookie様のファイルの読み書きセットを考えました。
         これですと、データは同じフォルダー内のmyCookie.txtにデータの読み書きができますので、確認も容易です。

         下のコードは、htaのコードです。htaの記述はhtmlの記述とほぼ同じで、拡張子を .htaに変えとhtaになります。
         htaでは、ActiveXを使っても警告が表示されないメリットがあります。
          IEでは、htmlやhtaではJavaScriptのコードとして、標準のJavaScriptのコードとJScriptのコードを混在して記
         述ができます。このため、FSOなどをActiveXとして記述できます。 
          このFSOの記述は、VBScriptのコマンド名に類似しますが、いくつかの記述規則が異なります。
          下のコードはFSOをJScriptとして記述した例です。

          作成したコードでは、2つの関数をセットすれば、setCookie("IMGNO",sA);でキーIMGNOでsAの値をセットし、
         sB = getCookie("IMGNO"); でキーIMGNOの値を取得できます。
                       関数部分を別なファイルmyCookie.jsとして、JS参照とすれば、本文のコードを短くして使用できます。

<html>
<head><title>myCookieを使う</title>
<hta:application id="myHTA">
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis">
<meta http-equiv="Content-Style-Type" content="text/css"><!-- CSS記述の定義 -->
<script language="JavaScript"><!--
onload = function() {
 var sA =String(31);
 var sK ="IMGNO"
   setCookie(sK,sA);
 var sB = getCookie("IMGNO");
 alert(sB);
 
}
function getCookie(sKey) {
 ForReading =1; ForWritin =2; ForAppending =8;
 var fso = new ActiveXObject("Scripting.FileSystemObject");
 var appPath =fso.GetFolder(".").Path //カレントフォルダーを取得
 var a = fso.OpenTextFile(appPath +"/myCookie.txt", ForReading, false);
    var sC = a.readAll();
 a.Close();
 var sAns= sC.substring( sC.indexOf("=", sC.indexOf(sKey)+1)+1, sC.indexOf(";", sC.indexOf(sKey) ));
 return sAns;
}
function setCookie(sKey,sWord) {
 // パス記述は"E:/JavaScript1008/myCookie.txt";のように /.../ です。
 var sA =sKey +"=" +sWord +";"
 //location.pathnameを使う
   // htaでは"E:\JavaScript\myCookie.hta"が得られる
 // htmlでは"E:/JavaScript/myCookie.hta"が得られる
 var appPath =window.location.pathname;
 //myHTA.commandLineを使う htaでは"E:\JavaScript\myCookie.hta"が得られる
 //var appPath =myHTA.commandLine;
 //末尾のファイル名を削除
 var localPath =appPath.substring(0, appPath.lastIndexOf("\\", 99));
 // "\"を"/"に替える (正規検索・置換)
 var localPath = localPath.replace(/\\/g, "\/");
 // htmlでは末尾のファイル名を削除を削除のみで使用する。
 // var localPath =appPath.substring(1, appPath.lastIndexOf("/"));
 ForReading =1; ForWritin =2; ForAppending =8;
 var fso = new ActiveXObject("Scripting.FileSystemObject");
 //GetFolder(".").Pathを使う  "E:\JavaScript"が得られる
 //var appPath =fso.GetFolder(".").Path
 //var localPath = appPath.replace(/\\/g, "\/");   //何故かこの置換は不用でもある
 var a = fso.OpenTextFile(localPath +"/myCookie.txt", ForReading, false);
    var sC = a.readAll();
 a.Close();
    var sD;
 if(sC.indexOf(sKey) >-1) {
  var n1 = sC.indexOf(sKey);
  var n2 = sC.indexOf(";", n1);
  var sP = sC.substring(n1,n2+1);
  sD = sC.replace(sP,sA);
 }else {
  sD = sC + sA;
 }
 var a = fso.OpenTextFile(localPath +"/myCookie.txt", ForWritin, true);
 a.Write(sD);
 a.Close();
 fso =null;
}
// --></script>
<style type="text/css">BODY {
 FONT-SIZE: 13px; LINE-HEIGHT: 130%
}
</style>
</head>
<body >
</body></html>

         上のコードでは、htaで使える3種のカレントディレクトリーの取得方法をメモとして書いてあります。
         htaでは「GetFolder(".").Pathを使う」のが最も簡単ですが、これはhtmlでは使用できません。
          「location.pathnameを使う」記述はhtaとhtmlの双方で使用できますが、取得した文字列の処理が一部だけ
        異なります。  面倒ですが、カレントディレクトリーが得られないとFSOのファイル操作ができません。


[ プログラムが異なるroot directoryに置かれた場合の対応 ]

         作成したhtmlやhta プログラムを使用してもらう際に問題となるのは、機種での動作デレクトリーの違いです。
        画像ファイルフォルダーが複数で沢山ある場合には、管理CSVを作成し、ここに品種別などで納められている
        フォルダーを作成して置き、これを読み取ります。
         一番単純な方法としては、複数の画像フォルダーと主プログラムを特定の位置に並列して置くことですが、これ
        では、あまり自由度が低くなります。
         下のように、JavaScriptの1行のコードを記述し、init.js などとして置き、主プログラムにJS参照をセットする方法
        は容易に考えつきます。 この方式であれば、別ファイルのJSファイルを開き、ユーザーに一度だけ編集してもらえ
        ば解決されます。(主プログラムのコードを見せなくてすみます。)

var jpgPath='E:/';    // 'E:/' と/まで記述すること

         これを自動的に書き直す方式を考えると、次のコードになります。

function init( ) {
     //initCamSum.jsのjpgPath記述のrootDirectoryが異なる場合にはCapを書き換える
     var rootCap = window.location.pathname.substring(0,1);//現在のappPathから E, Dなどを取得
     var sA =getCookie("jpgPath");  //init.jsの項目をmyCookieで読む
     var sW =sA.charAt(1);              //'E:/'などからEなどの文字を読む
     if ( rootCap !=sW) {
       sA = sA.replace(sW,rootCap); //置換して
       setCookie("jpgPath", sA);       //init.jsの項目をmyCookieで書き直す
       //書き直した jpgPathを読み直す
       jpgPath = getCookie("jpgPath");
       jpgPath =jpgPath.replace(/\'/g, "");//両端の'を空文字で置換(削除)
 }
 ・・・・・・・・・・・・・・・・

         現在のプログラムのカレント・ディレクトリーのルート文字と、init.jsに記述のルート文字が異なっている場合には、
        ルート文字を置き換えます。 その後に再度書き直したルート・パスを読み直します。
         これで、ルートが異なっても可動できますが、意地を張って面倒なことをしている感じは否定できません。

 



  覚書と謝辞
 
 WSH-VBScript は便利なツールです。VBScriptはいわば機能の繋ぎの言語ですが、いざ使おうとすると、基本的なコードの記述で躓きます。
 VBScript の二元配列の初期値の設定の記述など、Web検索してもなかなか該当する記述法が見出せません。情報は分散しており、その情報源を思い出すのに苦労します。 同じ思いをされる人も多いかと思い、面倒ですが、ここにまとめておきました。
 長くなるので、1つ1つの事項の参照Webを省きました、ここに各サイトの諸氏に感謝を述べさせて頂きます。


 

                                                   
                                                                                                                 

作成とこ