ボンジュール・マドモアゼル

本サイトの情報は自己責任にてご利用下さい。

[VBScript] VBScript Windows ファイルパス比較

 
Windowsのファイルパスには、次のような仕様がある。
次のパス名はすべて同じファイルを示すものとして解釈される:
  1. d:\InetPub\wwwroot\secret\data.txt
     基本形
  2. d:\inetpub\WWWROOT\SECRET\DATA.TXT
     大文字小文字は同一視される
  3. d:/InetPub/wwwroot/secret/data.txt
     ディレクトリの区切りに「/」も使える
  4. d:\\InetPub\\\wwwroot\\\\secret\\\\\data.txt
     ディレクトリの区切り文字は幾つか重複しても構わない
  5. d:////InetPub///wwwroot//secret/data.txt
     「/」も重複できる
  6. d:\InetPub\.\wwwroot\.\.\secret\.\.\.\data.txt
     「カレントディレクトリ」を表す . を差し挟むことができる
  7. d:\fake\fake\..\..\InetPub\wwwroot\secret\data.txt
     実在しないディレクトリもあとで「..」で遡れば指定可能

http://www.ipa.go.jp/security/awareness/vendor/programmingv1/b08_01.html


以下は、上記の仕様に則ってファイルパスの比較を行うVBScriptのサンプルコード。少し修正すればVBAでも使えるはず。
'FilePathComp.vbs

Option Explicit

Call Test("C:WindoWSSystEm32", "C://///Windows////System32")
Call Test("C:WindowsWeb..SystEm32", "C:///Windows.SysTEM32")

Function FilePathsAreSame(FilePath1, FilePath2)
FilePathsAreSame = (StrComp(CanonicalizeFilePath(FilePath1), _
CanonicalizeFilePath(FilePath2), _
vbBinaryCompare) = 0)
End Function


Private fs
Function CanonicalizeFilePath(FilePath)
If IsEmpty(fs) Then
Set fs = CreateObject("Scripting.FileSystemObject")
End If
CanonicalizeFilePath = LCase(fs.GetAbsolutePathName(FilePath))
End Function


Sub Test(FilePath1, FilePath2)
Dim Paths(1)
Paths(0) = FilePath1
Paths(1) = FilePath2

WScript.Echo "FilePathsAreSame(""" & Paths(0) & _
""", """ & Paths(1) & """) ==> " & _
FilePathsAreSame(Paths(0), Paths(1))
Dim i
for i = 0 to 1
WScript.Echo "CanonicalizeFilePath(""" & Paths(i) & """)" & _
vbTab & "==> " & CanonicalizeFilePath(Paths(i))
Next
WScript.Echo
End Sub
出力結果
C:\>cscript FilePathComp.vbs

Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

FilePathsAreSame("C:\\\WindoWS\\\\\SystEm32", "C://///Windows////System32") ==> True
CanonicalizeFilePath("C:\\\WindoWS\\\\\SystEm32") ==> c:\windows\system32
CanonicalizeFilePath("C://///Windows////System32") ==> c:\windows\system32

FilePathsAreSame("C:\Windows\Web\..\SystEm32", "C:///Windows\\.\SysTEM32") ==> True
CanonicalizeFilePath("C:\Windows\Web\..\SystEm32") ==> c:\windows\system32
CanonicalizeFilePath("C:///Windows\\.\SysTEM32") ==> c:\windows\system32
  1. 2012/03/20(火) 09:28:04|
  2. VBScript|
  3. トラックバック(-)|
  4. コメント:0

[VBScript] VBScript RegExp MultiLine まとめ

 
MultiLine を有効にすると、ラインフィード(LF)で区切られた入力文字列を複数行として扱う。
^, $が文字列の全体の始端と終端にマッチする特殊文字から、
文字列内の各行の始端と終端にマッチする特殊文字に変化する。

注意事項

以下、確認用のサンプルコード。出力結果を先に確認する方が分かりやすい。
' TestRegExp.vbs


Option Explicit

Dim re
Set re = CreateObject("VBScript.RegExp")
Dim Patterns(1)

Main

Public Sub Main()

re.Global = True
re.IgnoreCase = True

Patterns(0) = "^a.*b$"
Patterns(1) = "^a(?:.|x0A)*b$"

WScript.Echo "以下では <Cr> は文字コード 0x0D を示し <Lf> は文字コード 0x0A を示す。"

Test "a1b" & vbCrLf & "a2b" 'vbCrLf = 0x0D0A
Test "a1b" & vbCr & "a2b" 'vbCr = 0x0D
Test "a1b" & vbLf & "a2b" 'vbLf = 0x0A

End Sub

Sub Test(s)
WScript.Echo String(50, "-")
WScript.Echo "String:""" & ToPrintString(s) & """"
WScript.Echo

re.Multiline = False
TestSub s

re.Multiline = True
TestSub s

End Sub

Sub TestSub(s)
Dim i
For i = LBound(Patterns) To UBound(Patterns)
re.Pattern = Patterns(i)
PrintResult s
Next
End Sub

Sub PrintResult(s)
WScript.Echo vbTab & "Multiline:" & vbTab & vbTab & re.Multiline
WScript.Echo vbTab & "Pattern:" & vbTab & vbTab & re.Pattern
WScript.Echo vbTab & "Test(""" & ToPrintString(s) & """):" & vbTab & re.Test(s)
WScript.Echo vbTab & "MatchCollection:" & vbTab & ToPrintString(MatchCollectionToString(re.Execute(s)))
WScript.Echo
End Sub


Function MatchCollectionToString(mtchs)
If mtchs.Count > 0 Then
Dim buf()
ReDim buf(mtchs.Count - 1)

Dim i
For i = 0 To mtchs.Count - 1
buf(i) = "[" & mtchs(i) & "]"
Next
MatchCollectionToString = Join(buf, ", ")
End If
End Function


Function ToPrintString(s)
Dim t
t = s
t = replace(t, vbCr, "<Cr>")
t = replace(t, vbLf, "<Lf>")
ToPrintString = t
End Function
出力結果
C:\>cscript TestRegExp.vbs

Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

以下では <Cr> は文字コード 0x0D を示し <Lf> は文字コード 0x0A を示す。
--------------------------------------------------
String:"a1b<Cr><Lf>a2b"

Multiline: False
Pattern: ^a.*b$
Test("a1b<Cr><Lf>a2b"): False
MatchCollection:

Multiline: False
Pattern: ^a(?:.|\x0A)*b$
Test("a1b<Cr><Lf>a2b"): True
MatchCollection: [a1b<Cr><Lf>a2b]

Multiline: True
Pattern: ^a.*b$
Test("a1b<Cr><Lf>a2b"): True
MatchCollection: [a1b], [a2b]

Multiline: True
Pattern: ^a(?:.|\x0A)*b$
Test("a1b<Cr><Lf>a2b"): True
MatchCollection: [a1b<Cr><Lf>a2b]

--------------------------------------------------
String:"a1b<Cr>a2b"

Multiline: False
Pattern: ^a.*b$
Test("a1b<Cr>a2b"): True
MatchCollection: [a1b<Cr>a2b]

Multiline: False
Pattern: ^a(?:.|\x0A)*b$
Test("a1b<Cr>a2b"): True
MatchCollection: [a1b<Cr>a2b]

Multiline: True
Pattern: ^a.*b$
Test("a1b<Cr>a2b"): True
MatchCollection: [a1b<Cr>a2b]

Multiline: True
Pattern: ^a(?:.|\x0A)*b$
Test("a1b<Cr>a2b"): True
MatchCollection: [a1b<Cr>a2b]

--------------------------------------------------
String:"a1b<Lf>a2b"

Multiline: False
Pattern: ^a.*b$
Test("a1b<Lf>a2b"): False
MatchCollection:

Multiline: False
Pattern: ^a(?:.|\x0A)*b$
Test("a1b<Lf>a2b"): True
MatchCollection: [a1b<Lf>a2b]

Multiline: True
Pattern: ^a.*b$
Test("a1b<Lf>a2b"): True
MatchCollection: [a1b], [a2b]

Multiline: True
Pattern: ^a(?:.|\x0A)*b$
Test("a1b<Lf>a2b"): True
MatchCollection: [a1b<Lf>a2b]
  1. 2012/03/17(土) 12:06:29|
  2. VBScript|
  3. トラックバック(-)|
  4. コメント:0

[VBScript] Dictionary オブジェクトがコレクションではありません。(800A01C3)

 
Set dict = CreateObject("Scripting.Dictionary")

dict.Add 1, "a"
Msgbox dict.Items(0)
上記の VBSciprt ファイルを実行すると以下のエラーが発生します。(エラーメッセージが表示されない場合は、既定のホストが CScript になっている可能性があります。既定のホスト切り替えについては、『WSH エラーメッセージを表示する』を参照して下さい。)

エラーメッセージ
エラー: オブジェクトがコレクションではありません。: 'dict.Items'
コード: 800A01C3

解決策
もともと Dictionary オブジェクトの Items(), Keys()メソッドには引数はありません。戻り値は要素ではなく要素の配列になります。そこで以下のように Items メソッドの呼び出しで引数なしの括弧を補えば解決します。
Set dict = CreateObject("Scripting.Dictionary")

dict.Add 1, "a"
Msgbox dict.Items()(0)
Itemsメソッドの返す配列を何度も参照する場合には、Itemsメソッドの戻り値を一時変数に格納するのも良いでしょう。

参考
MSDN : Script Runtime → Dictionary Object → Items Method (日本語)

MSDN : Script Runtime → Dictionary Object → Items Method (英語)