reading between two values - vbscript

I have to read between 2 values after asking the users if he want between the '' or not between.
Exemple if the user select 1 in the text
'Hi' My name is 'Kev'in and i'm happ'y' to be 'there'
he will have
'Hi' 'Kev' 'y' 'there'
in a text file. If he chose 2, he will have
My name is in and i'm happ to be
Right now I'm using
Do While objScriptFile.AtEndOfStream <> True
strCurrentLine = objScriptFile.ReadLine
intIsComment = InStr(1,strCurrentLine,"'")
If intIsComment > 0 Then
objCommentFile.Write strCurrentLine & vbCrLf
End If
Loop
Else
For now it's only reading both of the value (between '' and not between) but I have no idea how to change it.

That's pretty simple, provided the delimiter is unique. Split the line at ' and output either the even or the odd array elements, depending on whether 1 or 2 was chosen.
...
strCurrentLine = "'Hi' My name is 'Kev'in and i`m happ'y' to be 'there'"
arr = Split(strCurrentLine, "'")
For i = choice To UBound(arr) Step 2
objCommentFile.Write arr(i)
Next
...
The value of choice is your users' selection (either 1 or 2).
Note that for this to work the strings must not contain apostrophes anywhere else. As #Ekkehard.Horner pointed out in his comment you can't use the delimiter character elsewhere in the text (i'm), because otherwise it would be impossible to distinguish where it was intended to be a delimiter and where not.

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 = "..."

Classic ASP InStr() Evaluates True on Empty Comparison String

I ran into an issue with the Classic ASP VbScript InStr() function. As shown below, the second call to InStr() returns 1 when searching for an empty string in a non empty string. I'm curious why this is happening.
' InStr Test
Dim someText : someText = "So say we all"
Dim emptyString : emptyString = ""
'' I expect this to be true
If inStr(1,someText,"so",1) > 0 Then
Response.write ( "I found ""so""<br />" )
End If
'' I expect this to be false
If inStr(1, someText, emptyString, 1) > 0 Then
Response.Write( "I found an empty string<br />" )
End If
EDIT:
Some additional clarification: The reason for the question came up when debugging legacy code and running into a situation like this:
Function Go(value)
If InStr(1, "Option1|Option2|Option3", value, 1) > 0 Then
' Do some stuff
End If
End Function
In some cases function Go() can get called with an empty string. The original developer's intent was not to check whether value was empty, but rather, whether or not value was equal to one of the piped delimited values (Option1,Option2, etc.).
Thinking about this further it makes sense that every string is created from an empty string, and I can understand why a programming language would assume a string with all characters removed still contains the empty string.
What doesn't make sense to me is why programming languages are implementing this. Consider these 2 statements:
InStr("so say we all", "s") '' evaluates to 1
InStr("so say we all", "") '' evaluates to 1
The InStr() function will return the position of the first occurrence of one string within another. In both of the above cases, the result is 1. However, position 1 always contains the character "s", not an empty string. Furthermore, using another string function like Len() or LenB() on an empty string alone will result in 0, indicating a character length of 0.
It seems that there is some inconsistency here. The empty string contained in all strings is not actually a character, but the InStr() function is treating it as one when other string functions are not. I find this to be un-intuitive and un-necessary.
The Empty String is the Identity Element for Strings:
The identity element I (also denoted E, e, or 1) of a group or related
mathematical structure S is the unique element such that Ia=aI=a for
every element a in S. The symbol "E" derives from the German word for
unity, "Einheit." An identity element is also called a unit element.
If you add 0 to a number n the result is n; if you add/concatenate "" to a string s the result is s:
>> WScript.Echo CStr(1 = 1 + 0)
>> WScript.Echo CStr("a" = "a" & "")
>>
True
True
So every String and SubString contains at least one "":
>> s = "abc"
>> For p = 1 To Len(s)
>> WScript.Echo InStr(p, s, "")
>> Next
>>
1
2
3
and Instr() reports that faithfully. The docs even state:
InStr([start, ]string1, string2[, compare])
...
The InStr function returns the following values:
...
string2 is zero-length start
WRT your
However, position 1 always contains the character "s", not an empty
string.
==>
Position 1 always contains the character "s", and therefore an empty
string too.
I'm puzzled why you think this behavior is incorrect. To the extent that asking Does 'abc' contain ''? even makes sense, the answer has to be "yes": All strings contain the empty string as a trivial case. So the answer to your "why is this happening" question is because it's the only sane thing to do.
It is s correct imho. At least it is what I expect that empty string is part of any other string. But maybe this is a philosophical question. ASP does it so, so live with it. Practically speaking, if you need a different behavior write your own Method, InStrNotEmpty or something, which returns false on empty search string.

Validating the format of a userform textbox entry

I have a UserForm for a database data extractor I'm making. In it there is a TextBox for typing in the part number that the user wants to extract data for. I want to validate that the user has entered the correct format of part number before the bulk of the extractor runs. To do this I need a code to validate that the text is entered in the specific format:
3 Numeric Characters
1 Alphabetic Character or 1 Hyphon
then 5 Numeric Characters
I tried the following validations at first:
'validate that box is not empty
If TextBox1.Value = "" Then
MsgBox ("Sorry, you need to provide an Amount")
TextBox1.SetFocus
Exit Sub
End If
'validate that box is numeric
If Not IsNumeric(TextBox1.Value) Then
MsgBox ("Sorry, must enter a numer")
TextBox1.SetFocus
Exit Sub
End If
But then I realised that I had the problem that there may be an alphabetic char or hyphon in the fourth position.
I would appreciate any suggestions.
Thanks in advance.
A beginner way to check this input is to just chop up the input string and compare the parts as needed:
Const alpha as String = "abcdefghijklmnopqrstuvwxyz-"
Dim strValue as String
Dim msg as String
strValue = TextBox1.Value
'Make sure it's the right LENGTH
If Len(strValue) <> 9 Then
msg = "Please enter the ID as 3 numeric, 1 alpha/hyphen, 5 numeric"
GoTo EarlyExit
End If
'Check the first three for numeric:
If Not IsNumeric(Left(strValue), 3) Then
msg = "The first three characters should be numeric"
GoTo EarlyExit
End If
'Check the middle character, assuming case not sensitive:
If Instr(1, alpha, Lcase(Mid(strValue, 4, 1)) = 0 Then
msg = "The fourth character should be hyphen or alphabet"
GoTo EarlyExit
End If
'Check the last four characters
If Not IsNumeric(Right(strValue, 4)) Then
msg = "The last four characters should be numeric"
GoTo EarlyExit
End If
'If you've gotten here, then the input is validated:
Exit Sub
EarlyExit:
MsgBox msg
TextBox1.SetFocus
End Sub
3 Numeric Characters 1 Alphabetic Character or 1 Hyphon then 5 Numeric Characters

VBScript to combine rs values, loop and add to duplicate(s)

I've written a lot of IF statements in VBScript, but haven't gone much beyond that so apologize for my lack of experience. I hope what I'm asking is simple to do.
I want to output item identifiers created by three combined recordset field values and add "B" "C" "D" etc., to any duplicates. Duplicates are rare, but do happen occasionally. I want to do this for meaningful item identification which autonumbers do not provide.
The following example works to combine fields, but then I need to include script to loop and find the duplicates and add the appropriate alpha character.
FYI: a = alpha character, b = alpha character, c = reformatted date
<% Dim idCode
a = (rs_table.Fields.Item("CodeA").Value)
b = (rs_table.Fields.Item("CodeB").Value)
c = (fixedDate(rs_table.Fields.Item("Date").Value))
idCode = (a) & (b) & (c)
Response.write idCode
%>
example output: LC032414
example dupe output: LC032414B
Thanks, I'm almost afraid to ask and may find this more pain than what it's worth!
I would probably use a Dictionary to store the ID's, since you can add each as a key (which must be unique) and test the Dictionary for its existence. Something like this:
' Early on... create a dictionary...
Set d = CreateObject("Scripting.Dictionary")
' Loop through your records...
Do Until rs_table.EOF
' Determine your ID...
idCode = rs_table("CodeA") & rs_table("CodeB") & fixedDate(rs_table("Date"))
' Check for existence in the dictionary...
If d.Exists(idCode) Then
' ID already exists. Keep testing suffixes until we find an availability...
strLetter = "B"
Do While d.Exists(idCode & strLetter)
strLetter = Chr(Asc(strLetter) + 1)
Loop
d.Add idCode & strLetter, "" ' Add the ID/key. The value is unimportant.
Else
' This ID doesn't exist yet. Just add it.
d.Add idCode, "" ' Add the ID/key. The value is unimportant.
End If
rs_table.MoveNext
Loop
When it comes time to print your ID's, you can just iterate the dictionary's Keys collection:
For Each k In d.Keys
Response.Write k
Next

vbscript - Replace all spaces

I have 6400+ records which I am looping through. For each of these: I check that the address is valid by testing it against something similar to what the Post Office uses (find address). I need to double check that the postcode I have pulled back matches.
The only problem is that the postcode may have been inputted in a number of different formats for example:
OP6 6YH
OP66YH
OP6 6YH.
If Replace(strPostcode," ","") = Replace(xmlAddress.selectSingleNode("//postcode").text," ","") Then
I want to remove all spaces from the string. If I do the Replace above, it removes the space for the first example but leave one for the third.
I know that I can remove these using a loop statement, but believe this will make the script run really slow as it will have to loop through 6400+ records to remove the spaces.
Is there another way?
I didn't realise you had to add -1 to remove all spaces
Replace(strPostcode," ","",1,-1)
Personally I've just done a loop like this:
Dim sLast
Do
sLast = strPostcode
strPostcode = Replace(strPostcode, " ", "")
If sLast = strPostcode Then Exit Do
Loop
However you may want to use a regular expression replace instead:
Dim re : Set re = New RegExp
re.Global = True
re.Pattern = " +" ' Match one or more spaces
WScript.Echo re.Replace("OP6 6YH.", "")
WScript.Echo re.Replace("OP6 6YH.", "")
WScript.Echo re.Replace("O P 6 6 Y H.", "")
Set re = Nothing
The output of the latter is:
D:\Development>cscript replace.vbs
OP66YH.
OP66YH.
OP66YH.
D:\Development>
This is the syntax Replace(expression, find, replacewith[, start[, count[, compare]]])
it will default to -1 for count and 1 for start. May be some dll is corrupt changing the defaults of Replace function.
String.Join("", YourString.Split({" "}, StringSplitOptions.RemoveEmptyEntries))
Because you get all strings without spaces and you join them with separator "".

Resources