Passing Multiple Variables to Case
-
30 Nisan 2012 Pazartesi 19:38
VBscript question; Code is at end of this question.
Instead of creating an entirely new Sub with hard-coded values for Case, I want to pass different variables, and different numbers of variables to the Sub for the Case to look for.
Instead of creating 3 unique Subs each with its own Case variables to look for:
'Case "c","e","s"
'Case "a","b"
'Case "a","z","b","e","j","f"
I want to make the Sub generic, and instead pass to the Case, whatever number of variables I please:
Dim lstrLook4MelstrLook4Me = "c","e","s"
Call sTester( "File", "d:\temp\New Text Document.vbs", "c:\users", "\desktop\", lstrLook4Me )
... snip ...
Case lstrLook4
=-=-=-=-=-=-=-=-=-=-
Option Explicit
Dim objShell : Set objShell = Wscript.CreateObject( "Wscript.Shell" )
Dim objFSO : Set objFSO = CreateObject( "Scripting.FileSystemObject" )Dim lstrLook4Me
lstrLook4Me = "c","e","s"
Call sTester( "File", "d:\temp\New Text Document.vbs", "c:\users", "\desktop\", lstrLook4Me )lstrLook4Me = "a","b"
Call sTester( "File", "d:\temp\New Text Document2.vbs", "c:\users", "\desktop\", lstrLook4Me )lstrLook4Me = "a","z","b","e","j","f"
Call sTester( "File", "d:\temp\New Text Document3.vbs", "c:\users", "\desktop\", lstrLook4Me )Sub sTester( bCopyType, lstrSrcObject, lstrDestProfilePath, lstrDestPath, lstrLook4 )
Dim objSubFolder
If objFSO.FolderExists( lstrDestProfilePath ) Then
For Each objSubFolder in objFSO.GetFolder( lstrDestProfilePath ).Subfolders
Select Case Left( LCase( objSubFolder.Name ),1 )
Case lstrLook4
'Case "c","e","s"
'Case "a","b"
'Case "a","z","b","e","j","f"
wscript.echo "Found: " & objSubfolder.Name
'objFSO.CopyFile lstrSrcObject , objSubfolder.Path & lstrDestPath , TRUE
End Select
Next
End If
Set objSubFolder = Nothing
End Subwscript.quit
'eof- Taşıyan Shanks ZenMicrosoft Contingent Staff 02 Mayıs 2012 Çarşamba 06:48 (From:Visual Basic General)
Tüm Yanıtlar
-
30 Nisan 2012 Pazartesi 19:54
@Moderator: Can you kindly move this to to the Scripting Guys forum?
As you've found, Select Case won't work. Instead, use a simple function such as the following to determine if a generic enumerable object contains a given item. The first version (ContainsScalar) is simpler but can't handle objects; the second version is more general and robust:
Function ContainsScalar( vEnumerable, vSearchItem ) Dim vItem For Each vItem In vEnumerable If vItem = vSearchItem Then ContainsScalar = True Exit Function End If Next ContainsScalar = True End Function Function Contains( vEnumerable, vSearchItem ) Dim vItem For Each vItem In vEnumerable If IsObject(vItem) Then If IsObject(vSearchItem) Then If vItem Is vSearchItem Then Contains = True Exit Function End If End If Else If Not IsObject(vSearchItem) Then If vItem = vSearchItem Then Contains = True Exit Function End If End If End If Next Contains = False End Function
Then you can update your test function like the following:
Sub sTester( bCopyType, lstrSrcObject, lstrDestProfilePath, lstrDestPath, arrFirstLetters ) Dim objSubFolder If objFSO.FolderExists( lstrDestProfilePath ) Then For Each objSubFolder in objFSO.GetFolder( lstrDestProfilePath ).Subfolders If ContainsScalar(arrFirstLetters, Left( LCase( objSubFolder.Name ),1 )) Then wscript.echo "Found: " & objSubfolder.Name End If Next End If Set objSubFolder = Nothing End Sub
jmh
- Düzenleyen Joshua Honig 30 Nisan 2012 Pazartesi 20:05
-
02 Mayıs 2012 Çarşamba 17:36
Thank you for your code; and for moving this to the Scripting Guys forum (it was down when I initially tried).
I'm leaning towards this right now:
Call sTester( "File", "d:\temp\New Text Document3.vbs", "c:\users", "\desktop\", "ces" )Sub sTester( bCopyType, lstrSrcObject, lstrDestProfilePath, lstrDestPath, lstrLook4 )
... replacing the entire Select Case statement with
If InStr( lstrLook4, Left( LCase( objSubFolder.Name ),1 ) ) > 0 Then
...
End If
I could separate the values passed to lstrLook4 with "|" as in "c|e|s" ; using reserved characters that cannot occur as a folder name; it creates a simple break should I want to compare against more than a single character string later.
I haven't tested it yet. I just had two other fires blow up to deal with. I'll report back here with the results as soon as possible.
- Düzenleyen Robert Sudbury 02 Mayıs 2012 Çarşamba 17:37
-
02 Mayıs 2012 Çarşamba 18:25Moderatör
Hi,
Unfortunately, VBScript doesn't support an indeterminate number of parameters passed to a Function or Sub procedure (JScript does, though). So you are right that you'll have to use some kind of workaround to get around the limitation. What I usually do is pass a delimited string (separated by vbTab or some other character such as ";" that you know can't appear in the string), use Split to return an array, and then iterate the array.
Bill
-
02 Mayıs 2012 Çarşamba 21:42
What you are trying to do with struings can best be doen with RegEx. Thisis what youare try8ing to reinvent from what I see of your code (pseudo code). It cannotbe actual code because ther are toomany syntax errors.
First one:
lstrLook4Me = "c","e","s"
This cannot be done in VBScript. PowerShell and other scripting system can do it but not VBScript.
¯\_(ツ)_/¯
-
03 Mayıs 2012 Perşembe 12:16
Well, there's no reason you can't use an actual array. jrv is correct that direct assignment of a comma-separated list doesn't work in VBScript (though it does in PowerShell). But all you have to do is put the items in the global Array function:
arrFirstLetters = Array( "c", "e", "s" ) Call sTester( "File", "d:\temp\New Text Document3.vbs", "c:\users", "\desktop", arrFirstLetters ) Sub sTester( bCopyType, lstrSrcObject, lstrDestProfilePath, lstrDestPath, arrFirstLetters ) ... If ContainsScalar(arrFirstLetters, LCase(Left(objSubFolder.Name, 1))) Then ... End If
jmh
-
03 Mayıs 2012 Perşembe 14:24Moderatör
Hi,
It's correct that you can return an array using the Array function, which works fine when the list of elements is defined before runtime. It's a little more difficult when the list of elements is defined at runtime; hence my suggestion of a delimited string and the Split function.
Bill
-
03 Mayıs 2012 Perşembe 14:39
So much code and so lfew capabilities.
RegEx is a great way to find these things as it takes only one line of code.
if rule.Test(string) Then
That's all.
We make our rule like this:
Set rule = New RegExp
rule.Pattern = "^C|^X|^Z"This says look for a c OR x OR x only at the beginining of the string "^" and use a case insensitive match.
We can declare this at teh begining of our code and call it anywhere as often as needed to test out tule in a one line test "rule.Test(somestring)
Put that together into a test harness and we are good to go.
'create test rig and declare match rules Set rule = New RegExp rule.IgnoreCase = True rule.Pattern = "^C|^X|^Z" ' we will use this array to test our match eengine. aFiles = Array( _ "a:\someplace\somefolder\comefile.xxt", _ "c:\someplace\somefolder\comefile.xxt", _ "d:\someplace\somefolder\comefile.xxt", _ "e:\someplace\somefolder\comefile.xxt", _ "f:\someplace\somefolder\comefile.xxt", _ "x:\someplace\somefolder\comefile.xxt", _ "z:\someplace\somefolder\comefile.xxt" _ ) 'loop through array and test each file name For Each f In aFiles If rule.Test(f) Then WScript.Echo ">>>>>>>Drive letter found!" Else WScript.Echo ".......Drive letter NOT found!" End If Next
Try it.¯\_(ツ)_/¯
-
03 Mayıs 2012 Perşembe 15:13
To show the power of this technique her is a little demo.
We know that WMI is very slow when searching the file system, Her is a ways to quickly serach through a hierarchy of folders for particulaar extensions that can be mosdified by just changing the search string.
Set rule = New RegExp rule.IgnoreCase = True rule.Pattern = "\.bmp$|\.jpg$|\.mp3$" Set fso = CreateObject("Scripting.FileSystemObject") Set folder = fso.GetFolder("c:\Windows") MatchFiles folder, rule Function MatchFiles(folder, rule ) On Error Resume Next For Each file In folder.Files If rule.Test(file) Then WScript.Echo file.Path End If Next For Each folder in folder.SubFolders MatchFiles folder, rule Next End FunctionNote that we can tell the rule to only look at the end of a string for a match ($) and we have to escape the . because it is a special character.
We can add as much complexity to the rule as we need to search for all kinds of compound criteria.
This is a case statement on steroids. Any set of functions you create to parse strings will only be reinventing RegEx.
RegEx has been part of computing since either the Dark Ages or the Middle Ages.. I can't remember which. I have been using REgEx since the Middle Ages - well, for at least 30 years.
http://en.wikipedia.org/wiki/Regular_expression
¯\_(ツ)_/¯
-
07 Mayıs 2012 Pazartesi 16:32Moderatör
Hi,
If I understand the OP's question, he is dealing with the fact that VBScript has no mechanism to pass an undefined number of parameters to a Sub or Function procedure. As noted in this thread, there are several workarounds:
- Pass an array. This is easier to use when the list of array elements is defined before runtime, and more awkward to use when the list of elements is defined at runtime.
- Pass a delimited string and use the Split function. This is awkward to use when the list of valid characters in an element is large.
- Use a regular expression. This is flexible and powerful but hampered by (IMO) VBScript's awkward regular expression object syntax.
(I would note, just for fun, that the original problem--passing an arbitrary number of parameters to a function--is not a problem in JScript.)
Does this cover it?
Bill
- Yanıt Olarak Öneren Bill_StewartMicrosoft Community Contributor, Moderator 09 Mayıs 2012 Çarşamba 21:19
- Yanıt Olarak İşaretleyen IamMredMicrosoft Employee, Owner 14 Mayıs 2012 Pazartesi 20:07
- Yanıt İşaretini Geri Alan Robert Sudbury 18 Mayıs 2012 Cuma 03:56
-
07 Mayıs 2012 Pazartesi 17:17
Hi,
If I understand the OP's question, he is dealing with the fact that VBScript has no mechanism to pass an undefined number of parameters to a Sub or Function procedure. As noted in this thread, there are several workarounds:
- Pass an array. This is easier to use when the list of array elements is defined before runtime, and more awkward to use when the list of elements is defined at runtime.
- Pass a delimited string and use the Split function. This is awkward to use when the list of valid characters in an element is large.
- Use a regular expression. This is flexible and powerful but hampered by (IMO) VBScript's awkward regular expression object syntax.
(I would note, just for fun, that the original problem--passing an arbitrary number of parameters to a function--is not a problem in JScript.)
Does this cover it?
Bill
I agree that the initial question appears to be about passing parameters but the problem or "why" i svery diffrent and the solution attempt is on the wrong path.
I also agree that with jscript we do not have this issue. With a WSF we can actually call from VBScript into Jscript functions.
The OP is trying to parse a string to detect the drive for a file path. The use of a function was his way of trying to handle multiple conditions of an indeterminate number. The conditions appeared to be string-like. The solution is best modeled by using a simple RegEx to detect the desired values in each string. The match string is adjustable and can have as many OR parts as is needed.
This:
rule.Pattern = "\.bmp$|\.jpg$|\.mp3$"
looks for any of these patterns at the end of the string being matched. It returns a simple true/false.For drive letter matching use this:
rule.Pattern ="^a|^b|^c|^d"
This says to look for these letters at the beginning of the string.
RegEx is the fastest and most flexible way to handle design patterns that are like this.
¯\_(ツ)_/¯
- Düzenleyen jrvMicrosoft Community Contributor 07 Mayıs 2012 Pazartesi 17:19
-
07 Mayıs 2012 Pazartesi 17:44Moderatör
Hi,
I am an advocate of regular expressions, but I recommend using them only when they are the most direct and obvious means of solving the problem. A good write-up summarizes the issue:
Regular Expressions: Now You Have Two Problems
HTH,
Bill
-
07 Mayıs 2012 Pazartesi 18:09
Hi,
I am an advocate of regular expressions, but I recommend using them only when they are the most direct and obvious means of solving the problem. A good write-up summarizes the issue:
Regular Expressions: Now You Have Two Problems
HTH,
Bill
Yes but, in my opinion, this was one of the good cases. It reduced the complexity of the problem and provided a very flexible solution. It is one of the reasons nearly all major subsystems use RegEx. XML, HTML, Net Framework, TSQL, Oracle ... etc. They have been with us since nearly the first days of computing. WordStar was built up from an early Unix lexical text processor that is an ancestor of todays Regular Expression processors. VI, TEDIT, - most major editors all use some form of RegEx.
¯\_(ツ)_/¯
-
07 Mayıs 2012 Pazartesi 19:30Moderatör
Yes but, in my opinion, this was one of the good cases.
Agree; as you say, it's a matter of opinion. I don't think I prefer a regexp solution in this case (particularly with VBScript's awkward regular expression object syntax). But to each his own.
Bill
-
07 Mayıs 2012 Pazartesi 19:48
Yes but, in my opinion, this was one of the good cases.
Agree; as you say, it's a matter of opinion. I don't think I prefer a regexp solution in this case (particularly with VBScript's awkward regular expression object syntax). But to each his own.
Bill
I don't understand what is so ugly. It look like most other regex parsers. You get one, assign a an expression and apply it to a string. No special things there. It is not the Unix or Perl version which takes options in the lead of teh expression but for most things we don't need options. Believe me. It can be a lifesaver when scriping. Throw out 20+ lines of code and debuggubg and just supply an expresion.
I used to use 'CoffeExpress" to test expressions. Now I use PowerShell Most expressions are portably between. With PosH around I find I use Regexp more an more all of the time.
¯\_(ツ)_/¯
-
07 Mayıs 2012 Pazartesi 19:59Moderatör
Awkward because it's a separate object (New RegExp), so in order to use it you have to create the object, set its properties, call its methods, etc. Usable but awkward and rather verbose. Not the case in many other languages where regexp support is a built-in part of the language syntax.
Bill
- Düzenleyen Bill_StewartMicrosoft Community Contributor, Moderator 07 Mayıs 2012 Pazartesi 20:39 correction
-
07 Mayıs 2012 Pazartesi 20:18
Awkward because it's a separate object (New RegExp), so in order to use it you have to create the object, set its properties, call its methods, etc. Usable but awkward and rather verbose. Not the case in other languages where regexp support is a built-in part of the language syntax.
Bill
They mean other langugaes have a shortcut to an expersion parser. VB.Net, C#, C++ do not have builtin support.
PowerShell has support in all string objects with soem syntac sugar to simplify the operator access.
VBScript is:
Set r= New RegExp
r..Pattern = "some patter"
r.Test(string)Not very complicated and no more ugly looking than any other part of all VB languages.
VB is just ugly.
¯\_(ツ)_/¯
-
07 Mayıs 2012 Pazartesi 20:41Moderatör
No argument from me about the ugliness of VBScript. Of the built-in WSH languages, I think JScript is far more elegant and powerful.
Bill
-
07 Mayıs 2012 Pazartesi 20:46
Avsolutely - I always like jscript. We pretty much have to use it with ASP.NET which is a good thing.
¯\_(ツ)_/¯
-
18 Mayıs 2012 Cuma 03:57As I stated on May 2nd, I am distracted by another fire, and must put aside marking this thread for now. Please do not mark this arbitrarily. I will return to it.
-
18 Mayıs 2012 Cuma 12:06
As I stated on May 2nd, I am distracted by another fire, and must put aside marking this thread for now. Please do not mark this arbitrarily. I will return to it.
I recommend rethinking your question and starting a new topic with a better stated question. The solution posted here are pretty much all you can get out of VBScript.
¯\_(ツ)_/¯
-
18 Mayıs 2012 Cuma 14:32Moderatör
Hi,
I've read the thread again and it seems like the question is answered (and pretty thoroughly, I might add?). So that we don't have lingering unanswered posts in this forum, we need to go ahead and mark an answer for now. When you have time to address it later, please start a new question (referencing this thread if appropriate). Thanks for your understanding.
Bill
- Yanıt Olarak İşaretleyen Robert Sudbury 18 Mayıs 2012 Cuma 17:00
- Yanıt İşaretini Geri Alan Robert Sudbury 18 Mayıs 2012 Cuma 17:00
-
18 Mayıs 2012 Cuma 17:03
I'm not debating the validity of any of the solutions offered, but I'm not about to rush or ignore the testing necessary to select a proposed solution as the one best suited for my context, just to satisfy someone's epeen.
- Düzenleyen Robert Sudbury 18 Mayıs 2012 Cuma 17:04
-
18 Mayıs 2012 Cuma 17:19Moderatör
Hi,
Please keep in mind that a peer-to-peer discussion group has no service-level agreement. In this case I think we have provided several good potential answers to your question. You are free to choose the one you want to implement on any schedule of your choosing and start a new thread if you have further questions at any time.
Microsoft has the right to impose guidelines on these forums. One of these guidelines is to mark as "answered" questions that get answered, and this seems to be the case here.
Thanks for your understanding.
Bill
- Yanıt Olarak İşaretleyen IamMredMicrosoft Employee, Owner 25 Mayıs 2012 Cuma 20:30