Hey, Scripting Guy!

Scripting Guys が皆さんの質問にお答えします

Hey, Scripting Guy!

TechNet コラムへようこそ。このコラムでは、よく寄せられるシステム管理スクリプトに関する質問に Scripting Guys がお答えします。システム管理スクリプトについて質問がある場合は、scripter@microsoft.com (英語のみ) までお送りください。すべての質問に回答することはできないかもしれませんが、可能な限り対応いたします。

詳細情報

Hey, Scripting Guy! カテゴリ別アーカイブ

Hey, Scripting Guy! 日付別アーカイブ

Hey, Scripting Guy! ダウンロード

Spacer

*

条件に応じてテキスト ファイルに行を追加する方法はありますか

Hey, Scripting Guy! Question

Scripting Guy さん、よろしくお願いします。ファイルを読み取り、ファイルの内容に応じて、読み取ったファイルに数行のテキストを挿入できるスクリプトが必要です。そのようなスクリプトを教えてもらえますか。
-- JS

SpacerHey, Scripting Guy! AnswerScript Center

JS さん、こんにちは。今ごろはほとんどの方が、マイクロソフトが Yahoo! に対して、時価約 420 億ドルでの買収を提案したことを耳にされていると思います (提案の一部は株価に基づいているので、買収額は毎日変動する傾向にあります)。しかし、今のところ、Yahoo! は条件がさらに有利になるのを期待して粘っています。マイクロソフトの CEO、Steve Ballmer に宛てた書面には、「当社には株主に最大の利益をもたらす方法を選択するという責任を果たす義務があり、貴社または他社が、当社の全体的な価値よりも低い価格で当社を買収することに応じるつもりはない」と記載されていました。

もちろん、実際には (お金を含めて) 何も生産していない企業は、420 億ドルよりもはるかに価値がありますからね。

編集者注: ええ、このコラムを執筆している Scripting Guy は、またもや自分 (と編集者) を問題に巻き込もうとしているようです。前回は、このコラムを執筆している Scripting Guy が他の有名な Web サイトについて言及しただけで、その記事が直ちに削除されました。今回の内容を見られたら…。急いでお読みください。皆さんは今回の内容を実際に目にした数少ない読者の 1 人になるでしょうから。

マイクロソフトは、まだ Yahoo! によるこの最新の批判に回答していません。それが意味することはただ 1 つ、Scripting Guys の出番です。Yahoo! の社員にとってお金は重要ではないようです。お金が重要だったら、420 億ドルを受け取って満足しているでしょう。むしろ、彼らはお金よりも有利で有意義な条件が付くのを期待して粘っているようです。そういうわけで、Scripting Guys は交渉に介入することにしました。Yahoo! が私たちに会社全体を譲っていただける場合は、Yahoo! の株主全員に、自分用の Dr. Scripto ボブルヘッド人形を差し上げましょう。これには 420 億ドルでも買えないほどの価値があります。

: そうですね、厳密に言うと、本当は 420 億ドルあれば 40 億体以上の Dr. Scripto ボブルヘッド人形を買うことができます。でも、Yahoo! の社員にはだれにも言わないでおきましょう。いいですね。

とにかく、Yahoo! の取締役会の役員でこの記事を読んでいる方がいらっしゃったら、ご意見をお聞かせください。ただし、この提案には交渉の余地がないことをお知らせしておきます。これは私たちに交渉する意思がないためではなく、単に数体のボブルヘッド人形以外に交渉材料となるものがないためです。編集者は自分のレクサスを交渉材料にしてもいいと言っていますが、だれがそれを運転でき、いつ運転できるようになるかは皆さんのご想像にお任せします。

: 確かに、私たちが彼女にたずねなかったこともあり、実際には編集者は自分のレクサスを交渉材料にしてもいいと言っていません。しかし、編集者は協調的な人物なので、この件に関しては問題ないと思います。

ただし、これが彼女にバレた場合は別です。

編集者注: この記事が発見されても住む場所を確保できるよう、編集者は今後もレクサスが必要です。

もちろん、多くの方は、この差し迫った取引について心配していることでしょう。おそらく、「うーん、Scripting Guys が Yahoo! を買収したら、お金と権力を持つようになるだろう。そうなったら、システム管理スクリプトの製作に時間を割こうとしなくなるのではないだろうか」とお考えですね。ええ、まったくそのとおりです。私たちは契約書のインクも乾かないうちに、タヒチのビーチに行っているでしょう。しかし、現実には Yahoo! を (少なくとも今は) 所有していないので、JS さんの質問にお答えしましょう。

Const ForReading = 1 
Const ForWriting = 2 
 
Set objFSO = CreateObject("Scripting.FileSystemObject") 
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading) 
 
Do Until objFile.AtEndOfStream 
    strLine1 = objFile.ReadLine 
    If InStr(strLine1, "Medical") Then 
        strDuplicateLine = strLine1 
        strDuplicateLine = Replace(strDuplicateLine, "Medical", "Dental") 
   End If 
    strLine2 = objFile.ReadLine 
    strLine3 = objFile.ReadLine 
    strText = strText & strLine1 & vbCrLf & strLine2 & vbCrLf & strLine3 & vbCrLf 
     
    If strDuplicateLine <> "" Then 
        strText = strText & strDuplicateLine & vbCrLf & strLine2 & vbCrLf & strLine3 & vbCrLf 
    End If 
 
    strDuplicateLine = "" 
Loop 
 
objFile.Close 
 
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForWriting) 
objFile.Write strText 
objFile.Close

このスクリプトのしくみについて説明する前に、処理するテキスト ファイルの内容を見てみましょう。JS さんのテキスト ファイルは、次のようになっています。

Ken Myer, Medical, 1/1/1980 
date, 1/1/2000 
reference, 12345 
Pilar Ackerman, None, 1/1/1980 
date, 1/1/2000 
reference, 12346

ご覧のとおり、ファイルの内容は 3 行単位で特定の人物に関するレコードを表しています。1 行目にはその人物の名前、2 行目には日付、3 行目には参照番号が含まれています (1 行目については、この後すぐに説明します)。1 行目に Medical という単語が含まれている場合はこのレコードをコピーしますが、1 つ例外があります。コピーしたレコードでは、Medical という単語を Dental という単語に置き換える必要があります。つまり、スクリプトが目的どおり動作すると、Ken Myer のレコードは、次の 2 つのレコードになります。

Ken Myer, Medical, 1/1/1980 
date, 1/1/2000 
reference, 12345 
Ken Myer, Dental, 1/1/1980 
date, 1/1/2000 
reference, 12345

しくみがわかりましたか。Pilar Ackerman には何が起きたかというと、何も起きていません。彼女のレコードには Medical という単語が含まれていないので、彼女の情報はそのままになっています。

Pilar Ackerman, None, 1/1/1980 
date, 1/1/2000 
reference, 12346

おわかりいただけましたか。それは良かったです。では、このスクリプトでこのような作業を行う方法をご説明しましょう。

まず、テキスト ファイルを開くときに使用する必要がある、ForReading と ForWriting という 2 つの定数を定義します。それから、この次に行う作業は、以下の 2 行のコードを使用して Scripting.FileSystemObject オブジェクトのインスタンスを作成し、C:\Scripts\Test.txt ファイルを読み取り用として開くことです。

Set objFSO = CreateObject("Scripting.FileSystemObject") 
Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForReading)

テキスト ファイルを開いたら、ファイルの内容を 1 行ずつ確認する作業に取り掛かる必要があります。それには、ファイルのすべての行を読み取るまで (もう少し専門的に説明するなら、ファイルの AtEndOfStream プロパティの値が True になるまで) 実行するようにデザインされた Do Until ループを設定します。

Do Until objFile.AtEndOfStream

ループ内では、まず、ReadLine メソッドを使用してファイルの最初の行を読み取り、それを strLine1 という名前の変数に格納します。

strLine1 = objFile.ReadLine

続いて、InStr 関数を使用して、Medical という単語が strLine1 変数の値に含まれているかどうかを確認します。

If InStr(strLine1, "Medical") Then

この行に Medical という単語が含まれていない場合はどうなるのか、ですって。正直に言うと、何も起こりません。Medical という単語が見つからなかった場合は、このレコードに対して実行しなければならない処理が特にないためです。しかし、Medical という単語が見つかった場合は話が別です。その場合は、次の 2 行のコードを実行します。

strDuplicateLine = strLine1 
        strDuplicateLine = Replace(strDuplicateLine, "Medical", "Dental")

ここで何をしているのかというと、ご覧のとおり、ここではそれほど多くの処理を実行していません。1 行目では、strLine1 変数の値を strDuplicateLine という名前の変数に代入します。実際には、テキスト ファイルの 1 行目の仮想コピーが作成されます。2 行目では、strDuplicateLine 変数の値を取得して、Medical という単語を Dental という単語に置き換えます。この処理が終わると、strLine1 変数の値は次のようになります。

Ken Myer, Medical, 1/1/1980

一方、strDuplicateLine 変数の値は次のようになります。

Ken Myer, Dental, 1/1/1980

ええ、この処理は問題ありませんね。これで、Ken Myer の Medical という単語が含まれているレコードの 1行目と、Ken Myer の Dental という単語が含まれているレコードの 1行目を作成できました。

続いて使用するのは、次の 2 行のコードです。

strLine2 = objFile.ReadLine 
strLine3 = objFile.ReadLine

どちらのコード行についても、説明は必要ないでしょう。1 行目では、ReadLine メソッドを使用してテキスト ファイルの次の行を読み取ります。2 行目では、同じメソッドを使用してその次の行 (テキスト ファイルの 3 行目) を読み取ります。最終的には strLine2 変数の値は次のようになります。

date, 1/1/2000

また、strLine3 変数の値は、…。ええ、そのとおり、テキスト ファイルの 3 行目と等しくなります。

reference, 12345

: 本当にわかっていたのですか。それともただのまぐれ当たりだったのでしょうか。

これで、Ken Myer の両方のレコードを作成するのに必要な情報を、すべて取得できました (Medical という単語が見つからなかった場合は、単に 1 つのレコードを再作成するために必要な情報を取得できた、ということになりますが)。次のコード行を使用して、レコード 1 を作成できます。

strText = strText & strLine1 & vbCrLf & strLine2 & vbCrLf & strLine3 & vbCrLf

ここでは、新しい値を strText 変数に代入します。代入する値は、strText 変数の既存の値に、次の項目を追加したものです。

strLine1 変数の値 (Ken Myer, Medical, 1/1/1980) と復帰改行文字 (VBScript 定数の vbCrLf)

strLine2 変数の値 (date, 1/1/2000) と復帰改行文字

strLine3 変数の値 (reference, 12345) と復帰改行文字

つまり、strText 変数の値は次のようになります。

Ken Myer, Medical, 1/1/1980 
date, 1/1/2000 
reference, 12345

次は、strDuplicateLine 変数に値が格納されているかどうか (つまり、値が空の文字列ではないかどうか) を確認します。

If strDuplicateLine <> "" Then

strDuplicateLine 変数に値が格納されている場合、それが意味することはたった 1 つ、Medical という単語がこのレコードの 1 行目に見つかったということです。したがって、Dental という単語が含まれているレコードを追加する必要があります。これを行うのが次のコード行です。

strText = strText & strDuplicateLine & vbCrLf & strLine2 & vbCrLf & strLine3 & vbCrLf

おわかりでしょうか。この場合は、strDuplicateLine 変数を使用します (この変数は、Medical という単語を Dental という単語に置き換えるのに使用します)。この結果、strText 変数の値は次のようになります。

Ken Myer, Medical, 1/1/1980 
date, 1/1/2000 
reference, 12345 
Ken Myer, Dental, 1/1/1980 
date, 1/1/2000 
reference, 12345

いやあ、驚きましたね。Ken Myer のレコードが 2 つ (Medical という単語が含まれているレコードが 1 つと Dental という単語が含まれているレコードが 1 つ) になりました。期待どおりの結果です。

これを実行したら、strDuplicateLine 変数の値を空の文字列にリセットし、ループの先頭に戻り、テキスト ファイルの次の行に対して同じ処理を繰り返します (思い出していただくと、次の行というのは、実際にはテキスト ファイルの 4 行目になります。これは、1 〜 3 行目を既に読み取っているためです)。テキスト ファイル全体の読み取りが完了したら、Close メソッドを使用して Test.txt を閉じます。その後、次のコード行を使用して、今度は書き込み用として再びファイルを開きます。

Set objFile = objFSO.OpenTextFile("C:\Scripts\Test.txt", ForWriting)

その後、Write メソッドを使用して、ファイルの既存の内容を strText 変数の値で置き換え、最後にもう一度ファイルを閉じたら作業完了です。

Yahoo! との取引については、正直なところ、私たちは考え直し始めています。実は、私たちは Yahoo! の株主の人数を少なく見積もりすぎていました。私たちは 5 人か 6 人だと思っていましたが、Yahoo! には何十万人もの株主がいることが判明しました。それはどういうことかというと、私たちは全株主に行き渡るだけのボブルヘッド人形を持っていないということです。皆さんが分け合ってもよいのでしたら、問題ありません。そうでない場合は、これならどうでしょう。Yahoo! がスクリプト センターを買収するのはどうでしょうか。何しろ、皆さんの企業にあれほどけちな提案をしたことに対してマイクロソフトに仕返しをするには、最高の方法ですよね。ちょっと考えてみてください。マイクロソフトの最優良部門であるスクリプト センターを奪い取るなんて、値段が付けられない価値がありますね。

念のため言っておきますが、本当に値段が付かないわけではありませんよ。しかし、Scripting Guys はスクリプト センターが 420 億ドルでも喜んで受け入れます (確かに、スクリプト センターはもう少し価値がありますが、私たちは欲張りではありません)。それに、もう少し有利な条件をご提示しましょう。今月末までにご検討いただければ、この価格からさらに 5% 割り引きいたします。ぜひ、ご検討ください。


ページのトップへページのトップへ