none
Passing Multiple Variables to Case

    Soru

  • 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 lstrLook4Me

    lstrLook4Me = "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 Sub

    wscript.quit
    'eof

    • Taşıyan Shanks Zen 02 Mayıs 2012 Çarşamba 06:48 (From:Visual Basic General)
    30 Nisan 2012 Pazartesi 19:38

Yanıtlar

  • 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

    18 Mayıs 2012 Cuma 17:19

Tüm Yanıtlar

  • @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


    30 Nisan 2012 Pazartesi 19:54
  • 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.


    02 Mayıs 2012 Çarşamba 17:36
  • 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 18:25
  • 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.


    ¯\_(ツ)_/¯

    02 Mayıs 2012 Çarşamba 21:42
  • 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 12:16
  • 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:24
  • 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 14:39
  • 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 Function

    Note 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


    ¯\_(ツ)_/¯

    03 Mayıs 2012 Perşembe 15:13
  • 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:

    1. 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.
    2. 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.
    3. 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

    07 Mayıs 2012 Pazartesi 16:32
  • 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:

    1. 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.
    2. 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.
    3. 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 patt
    erns 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 jrv 07 Mayıs 2012 Pazartesi 17:19
    07 Mayıs 2012 Pazartesi 17:17
  • 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 17:44
  • 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 18:09
  • 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:30
  • 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:48
  • 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


    07 Mayıs 2012 Pazartesi 19:59
  • 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:18
  • 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:41
  • Avsolutely - I always like jscript.  We pretty much have to use it with ASP.NET which is  a good thing.


    ¯\_(ツ)_/¯

    07 Mayıs 2012 Pazartesi 20:46
  • 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.
    18 Mayıs 2012 Cuma 03:57
  • 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 12:06
  • 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 14:32
  • 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.


    18 Mayıs 2012 Cuma 17:03
  • 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

    18 Mayıs 2012 Cuma 17:19