Can a variable act as a space in VBS? - vbscript

I'm teaching myself VBS and I decided to write a message encryption program. It uses the left and right functions in a loop to read every individual character.
DO
wscript.sleep 100
if Az=0 then
EXIT DO
end if
CR=right(message,aZ)
DEL=left(CR,1)
aZ=aZ-1
zZ=zZ+1
supra=""
supra="supra"
CALL KEYCOUNT
CD=left(keyword,zZ)
TAC=right(CD,1)
....
From there, it sets every character equal to a different letter based on an encryption keyword and moves onto the next character. My problem is I don't know how to deal with spaces in the message. Is there a way to make a variable have the value of a space? I've tried:
set var=space(1)
set var="&"" ""&"
set var=""
set var=" "
set var=""" """
I'm certain there are things I'm not thinking of
Thanks
Joseph

set statement assigns an object reference to a variable or property, or associates a procedure reference with an event. That isn't our case.
var=space(1) ' var contains one space character
var="&"" ""&" ' var contains &" "&
var="" ' var contains a string of zero length
var=" " ' var contains one space character
var=""" """ ' var contains " "
Or, if you would like, declare a constant for use in place of literal value of space (anywhere in your script) as follows:
Const vbSp=" "
Constants are public by default. Within procedures, constants are always private; their visibility can't be changed. Within a script, the default visibility of a script-level constant can be changed using the Private keyword. There are variations:
Private Const vbSp=" "
Public Const vbSp=" "

The problem is that you use Set (cf. here) when assigning a simple/non-object value to a variable. If you loose it, your experimental statements will 'work' (compile & run without error). Look at the output and you'll see that
var = " "
is the correct and most efficient way to assign a (string containing one) space to a variable.

Related

VB Control Naming by Variable

Dim LineNo as Integer
LineNo = CStr(channel) 'This can have a value of 1 to 100
If LineNo = 1 then
Text1.Text = "Line one selected"
Elseif LineNo = 2 then
Text2.Text = "Line one selected"
'Etc etc
End if
I need to replace the number "1" in Text1.Text and every other TextBox with the value of LineNo? For example:
Text{LineNo}.Text
So I would not have to do a repeated "If" and have a smaller one line code like this:
Text{LineNo}.Text = "Line " & LineNo & " selected"
How would I do this?
Look into a Control array of text boxes. You could have txtLine(), for example, indexed by the channel number.
LineNo = CStr(channel)
txtLine(channel).Text = "Line " & LineNo & " selected"
To create the array, set the Index property of each of the text boxes to an increasing integer, starting at 0.
If you have a finite and relatively small number, you can use a property. I've used this approach with up to 30+ elements in a pinch. Super simple, easy pattern to recognize and replicate in other places. A bit if a pain if the number of elements changes in the future, but extensible nevertheless.
It uses the Choose statement, which takes an index N and returns the Nth element (1-based), hence, the check makes sure that N is > 0 and <= MAX (which you would configure).
Public Property Get TextBox txt(ByVal N As Long)
Const MAX As Long = 10
If N <= 0 || N > MAX Then Exit Property ' Will return a "Nothing". You could return the bound element if you prefer
set txt = Choose(Text1, Text2, Text3, Text4, Text5, Text6, Text7, Text8, Text9, Text10)
End Property
Then, you can simply reference them with the Property, much like an alias:
txt(1).Text = "Line 1 text"
txt(2).Text = "Line 2 text"
If you have an arbitrary number, then you are likely using a control array already, which is simpler because it can be referenced by Index already, so you can directly reference it.
If neither of these work for you and you have a very large number of controls, you can scan the Controls collection in a similar Property, attempting to match ctrl.Name with the pattern of your choice (e.g., matching the first 4 characters to the string "Text", thus matching Text1, Text2, etc, for an unlimited number). Theoretically, this should be future-proofed, but that's just theoretical, because anything can happen. What it does do for you is to encapsulate the lookup in a way that "pretends" to be a control array. Same syntax, just you control the value.
Public Property Get TextBox txt(ByVal N As Long)
Dim I As Long
For I = 0 To Controls.Count - 1 ' Controls is zero-based
' Perform whatever check you need to. Obviously, if you have a "Label" named
' "Text38", the assignment will throw an error (`TextBox = Label` doesn't work).
If Left(Controls(I).Name, 4) = "Text" Then
set txt = Controls(I)
End If
Next
' If you want the Property to never return null, you could uncomment the following line (preventing dereference errors if you insist on the `.Text` for setting/getting the value):
' If txt Is Nothing Then Set txt = Text1
End Property
Use the same way as above: txt(n).Text = "..."

VBScript create list, split list items and trim them

I'm trying to create code that would add variables to list. Then it would split all of list elements by :, returning only the second part. In the end all returned strings would be trimmed.
To give you better understanding let me show you an example:
Add "a : b " and " c : d " to the list.
Split elements so only "b " and "d " are returned.
Trim "b " and "d ".
So far I have came up with something like this but it doesn't work and I have no idea why.
Set list = CreateObject("System.Collections.ArrayList")
list.Add "bob : kid"
list.Add "ryan : alex"
list.Add "kate : andy"
list.Add "alice : mandy"
For Each item In list
Dim item As String
Dim words As String() = item.Split(New Char() {":"c})
For Each word In words
WScript.Echo word
Next
Next
Your code doesn't work because it's not valid VBScript. You have several issues:
VBScript doesn't support typed variable declarations (Dim var As Type). Use Dim var if you want to explicitly define a variable. Note, however, that in VBScript defining variables is only required when you put Option Explicit at the beginning of your script.
VBScript doesn't support combined declaration and definition of variables (Dim var = value). You need two separate statements for defining a variable and assigning a value to it. The two statements can be put in one line by separating them with a colon (Dim var : var = value), but they're still two separate statements.
In VBScript string is a primitive data type. VBScript strings are not objects with properties. For splitting a string use the Split() function.
Don't re-define your loop variable inside your loop.
Change your loop to something like this and it should do what you want:
For Each item In list
Dim words : words = Split(item, ":")
For Each word In words
WScript.Echo Trim(word)
Next
Next
If you want just the second element from each split item you'd do something like this:
Dim words : words = Split(item, ":")
WScript.Echo Trim(words(1))
or like this:
WScript.Echo Trim(Split(item, ":")(1))

single quote escaping in applescript/shell

I'm trying to process this shell script in applescript, but it keeps saying error EOF, because of the single quote in the folder name.
do shell script "cp -R " & a & " " & "'" & d & "/My 'Folder/java/" & "'"
The folder /My 'Folder/ is a legitimate directory.
The variable a = '/Applications/MyProgram/' (and includes the single quotes)
The variable d = /Folders (with no single quotes)
However, shell is getting stuck processing it, im guessing because the folder is enclosed in quotes.
Is there any way to escape this single quote, so it works in applescript using shell? Ive tried multiple backslashes but its not working.
Cheers
N
Always use quoted form of when using arbitrary data as an argument to an command. This will always quote the value even if it doesn't need to be quoted but it's better safe than sorry. When you have a string single quoted, you can only unquote (turn substitution mode back on) with another quote. Unlike AppleScript strings, you can't escape characters inside single quoted strings. So you need to turn substitution mode on, escape a quote and then turn substitution mode back one. For instance "Joe's car" should be quoted as "'Joe'\\''s car'". It's a quoted string "Joe" + escaped quote character + quoted string "s car". But like I started you should use quoted form of, quoted form of "Joe's car" will return "'Joe'\\''s car'"
Your command using quoted form will look like:
do shell script "cp -R " & quoted form of a & space & quoted form of (d & "/My 'Folder/java/")
The problem arises because you have that tick in the filename of course, on the terminal commandline you would use a tick - double-tick tick - double-tick tick sequence to present it.
(From the terminal below)
729$ echo 'My '"'"'Java Folder'
My 'Java Folder
In Applescript, and your command line, it becomes even more complicated, I recommend you echo your commandline, until you get back what you expect.
set res to (do shell script "echo 'My '\"'\"'Java Folder'")
log res
--> (*My 'Java Folder*)
I think you'll have to start out with that, and reconstruct how you escape the rest of the commandline around it, if it can't be just plugged in as it is.
You should also remove single quotes for entities, that doesn't need them, (no spaces). That way your commandline will become easier to both edit and read.
Adding an answer for JavaScript for AppleScript (JAX) users based on answer from McUsr:
debugger
var app = Application.currentApplication();
app.includeStandardAdditions = true;
var source = "/documents/John's Spreadsheet.xls";
var target = "/documents/John's Spreadsheet.csv";
source = source.replace("'", "'\"'\"'", "g");
target = target.replace("'", "'\"'\"'", "g");
var exportScript = "/excel -i";
exportScript += " '" + source + "'";
exportScript += " '" + target + "'";
exportScript += ";true";
try {
app.doShellScript(exportScript);
}
catch (error) {
console.log(error.message);
}
If you don't know what JAX is it's AppleScript but using JavaScript. Open Script Editor and select JavaScript from the dropdown beneath the record button.

Copy most recent file from a batch of alike files using vbscript

I am not sure if this is possible or not. I am not even sure where to begin. I have a couple thousand files where the file names are named as so:
nnnnnnnnnnnnnnnn.yyyyddmm.pdf (n = number, yyyy = year, dd = day, and mm = month).
Within these thousands of files, there are batches of alike files that have the same nnnnnnnnnnnnnnnnnn part of the filename but the .yyyyddmm is different in order to represent the date of the file. (These batches of alike files will be merged together at a later point but that is not important to this scenario).
My question is, Is there a way to compare the yyyyddmm part of the alike files and have the most recent date files get copied to a different folder? I need the file that has the most recent date of the alike files on the filename get copied to a different folder.
The reason that I am having issues with this is because I am not sure if it is possible to compare parts of the filename to see which one is in fact the file that has the most recent date. I know that there is a way that this can be done through looking at the date modified date but this will not always give me the alike file with the most recent date.
Any thoughts?? Please let me know if I could provide more information.
Trying to understand your problem/specs. Assume a loop over the files of your .pdf folder results in:
Looking at "0000000000012345.20120402.pdf"
Looking at "0000000000012345.20120502.pdf"
Looking at "0000000000012348.20121702.pdf"
Looking at "0000000000012346.20120802.pdf"
Looking at "0000000000012347.20121002.pdf"
Looking at "0000000000012348.20121602.pdf"
Looking at "0000000000012347.20121302.pdf"
Looking at "0000000000012347.20121202.pdf"
Looking at "0000000000012345.20120202.pdf"
Looking at "0000000000012348.20121502.pdf"
Looking at "0000000000012346.20120602.pdf"
Looking at "0000000000012346.20120902.pdf"
Looking at "0000000000012348.20121402.pdf"
Looking at "0000000000012346.20120702.pdf"
Looking at "0000000000012347.20121102.pdf"
Looking at "0000000000012345.20120302.pdf"
Would
Last file for 0000000000012345 is 0000000000012345.20120502.pdf
Last file for 0000000000012348 is 0000000000012348.20121702.pdf
Last file for 0000000000012346 is 0000000000012346.20120902.pdf
Last file for 0000000000012347 is 0000000000012347.20121302.pdf
identify the files to copy correctly? If yes, say so and I will post the code here.
First, you need a class to obtain and store the info put into the file names:
' cut & store info about file(names) like "0000000000012347.20121202.pdf"
Class cCut
Private m_sN ' complete file name
Private m_sG ' group/number prefix part
Private m_dtF ' date part; converted to ease comparisons
Public Function cut(reCut, sFiNa)
Set cut = Me ' return self/this from function
Dim oMTS : Set oMTS = reCut.Execute(sFiNa)
If 1 = oMTS.Count Then
m_sN = sFiNa
Dim oSM : Set oSM = oMTS(0).SubMatches
m_sG = oSM(0)
m_dtF = DateSerial(oSM(1), oSM(3), oSM(2))
Else
' Err.Raise
End If
End Function ' cut
Public Property Get G() : G = m_sG : End Property ' G
Public Property Get D() : D = m_dtF : End Property ' D
Public Property Get N() : N = m_sN : End Property ' N
End Class ' cCut
Then just loop over the .Files and check the date parts for each group stored in a dictionary (number prefix part used as key):
' The one and only .pdf folder - no recursion into subfolders!
Dim sTDir : sTDir = "..\data\test"
' dictionary to store the last/most recently used file for each group
Dim dicG : Set dicG = CreateObject("Scripting.Dictionary")
' RegExp to cut/parse file names like "0000000000012345.20120402.pdf"
Dim reCut : Set reCut = New RegExp
reCut.Pattern = "^(\d{16})\.(\d{4})(\d{2})(\d{2})\.pdf$"
Dim oFile
For Each oFile In goFS.GetFolder(sTDir).Files
WScript.Echo "Looking at", qq(oFile.Name)
' an oCut object for each file name
Dim oCut : Set oCut = New cCut.cut(reCut, oFile.Name)
If Not dicG.Exists(oCut.G) Then
' new group, first file, assume this is the latest
Set dicG(oCut.G) = oCut
Else
' found a better one for this group?
If dicG(oCut.G).D < oCut.D Then Set dicG(oCut.G) = oCut
End If
Next
WScript.Echo "-----------------------"
Dim sG
For Each sG In dicG.Keys
WScript.Echo "Last file for", sG, "is", dicG(sG).N
Next
WRT comments:
All my (ad hoc/proof of concept) scripts start with
Option Explicit
Dim goFS : Set goFS = CreateObject( "Scripting.FileSystemObject" )
and contain some functions dealing with different aspects/stragegies for a solution to a common problem/topic. When I post code here, I copy/paste working/tested code out of the middle of a function frame like
' ============================================================================
goXPLLib.Add _
"useDic02", "use a dictionary (Mark II)"
' ----------------------------------------------------------------------------
' ============================================================================
Function useDic02()
useDic02 = 1 ' assume error
' The one and only .pdf folder - no recursion into subfolders!
...
Next
useDic02 = 0 ' success
End Function ' useDic02
(yes, there is a first attempt function "useDic()" that was guilty of storing all the oCuts for each group to be processed in a second loop; yes, there is a function "createTestData()" I needed to set up/fill my TDir). Sometimes I'm sloppy and forget about goFS, please accept my apologies.
The variable names are part of an experiment. I used to advocate type-prefixed long variable names upto and including
Dim nIdx
For nIdx = 0 To UBound(aNames)
aNames(nIdx) = ...
Next
Other people argued that nIdx-alikes variables just add some letters to mistype but no additional meaning over i, and that aNames-alikes can't be understood without the context and if you have that, aN would be a just as good remainder for "The first names of the kings of persia from the currently processed file to be compared to the names in the database".
So I thought: Given that there are 3 interesting aspects of a file name (full name to copy, number prefix to group, date part to compare/decide) and that there is half a screen between
Private m_sN ' complete file name
and
Public Property Get N() : N = m_sN : End Property ' N
and given that you need just those 3 properties of the Cut object to use it in
Dim oCut : Set oCut = New cCut.cut(reCut, oFile.Name)
If Not dicG.Exists(oCut.G) Then
' new group, first file, assume this is the latest
Set dicG(oCut.G) = oCut
Else
' found a better one for this group?
If dicG(oCut.G).D < oCut.D Then Set dicG(oCut.G) = oCut
will the average short time memory cope with oCut.D?
Obviously not.
To copy the selected files:
Assuming you want the files copied to an existing folder "..\data\latest", use
goFS.CopyFile goFS.BuildPath(sTDir, dicG(sG).N), "..\data\latest\", True
instead of/in addition to the line
WScript.Echo "Last file for", sG, "is", dicG(sG).N
I did not anticipate that .CopyFile chokes on relative source pathes; so consider replacing the *N*ame property of the cCut class with a *P*ath property.
Trying to use
dicG(sG).Copy "..\data\latest\", True
results in:
Microsoft VBScript runtime error: Object doesn't support this property or method: 'dicG(...).Copy'
because the objects stored aren't files (which have a .Copy method), but cCuts (which don't).
How I would handle it:
I would make a dictionary with for each unique number part a separate key. The value will be an array with all file names sharing that key (and thus sharing the unique number part)
For each key in the dictionary, I will loop through the items in the array, searching for the most recent date.
Approach:
Get a file
Extract number part
See if a key for that number part exist. If not create a key for that number with an empty array as value
Add the filename as a new item to the array
Loop to 1. until all files are handled
Get a key
Get the first file in the attached array. Remember the date and the arrayindex
Get the next file, if the date is higher than the remembered date, update the date to this date and the arrayindex to this array index
Loop to 8. until the end of the array is reached
Store the file with the arrayindex as the most recent file for that unique number
loop to 6. until all keys are handled

How to use substring in vbscript within a xsl page

I am trying to replace the double quotes in a string with a single quote, got the following code but get error message saying "Object Required strLocation"
Sub UpdateAdvancedDecisions(strLocation)
Dim d
Dim strLLength
strLLength = Len(strLocation) - 1
For d = 0 To strLLength
alert strLocation
strValue = strLocation.Substring(2,3)
If strLocation.substring(d,d+1)=" " " Then
strLLength = strLLength.substring(0, d) + "'" + strLLength.substring(d + 1,strLLength.length)
Next
End Sub
As Helen said, you want to use Replace, but her example assigned the result to your weird strLLength variable. Try this instead:
strLocation = Replace(strLocation, """", "'")
This one line does the job you asked about and avoids all the code currently in your given subroutine.
Other things that are problems in the code you posted:
a variable holding a number like the length of a string would not have a "str" prefix, so strLLength is misleading
strings in VBScript are indexed from 1 through length, not 0 through length-1
there is no "alert" keyword in VBScript
you assign a value to strValue, then never use it again
you need to use Mid to get a substring, there is no "substring" string method in VBScript
c = Mid(strLocation, d, 1) ' gets one character at position d
The more I look at this, the more clear it is that its some JavaScript that you're trying to run as VBScript but are not translating at all correctly.
Use a reference for VBScript like one of the following:
MSDN Library: VBScript Language Reference
W3Schools VBScript Tutorial

Resources