VBScript function to read multiple strings not working properly - arrays

I have a function to read multiple string that I copied from another thread here.
I have the whole document that I need in a string name strResult, my intention is to compare only the fields on the strList, and find them in the strResult.
This is the function:
Function FindString(strCheck,strFind)
Arr = Split(strResult,",")
Flag = 0
And I call it like this: Call FindString(strResult,strList)
For Each str in Arr
If InStr(strCheck, str) > 0 Then
Flag = 1
Reporter.ReportEvent micPass,"Field Found","Field:"&str&" was found"
Else
Flag = 0
Reporter.ReportEvent micFail,"Field not Found","Field:"&str&" was not found"
End If
Next
If Flag = 1 Then
FindString = True
Reporter.ReportEvent micPass,"Field Found","Field"&str&"was found"
Else
FindString = False
Reporter.ReportEvent micFail,"Field not found","Field"&str&"was not found"
End If
It should return fail when the fields are not found, but it just ignores them, The list of string is on a variable that contains something like "field1,"&_"field2", the main problem is that even if "field3" is not in the strList, it will display it as found, and I only want it to take the fields that are on the strList not all of the strResult string

I fixed the function by splitting the list of values too, like this
Arr = Split(strCheck,",")
Arr2 = Split(strFind,",")
Flag = 0
For Each str in Arr
For Each str2 in Arr2
If InStr(str, str2) > 0 Then
Flag = 1
Reporter.ReportEvent micPass,"Field "&str2&" Found","Field:"&str&" was found"
Exit For
End If
Next

Related

How to compare array to array using VBScript?

I would like to check a data in my file exist or not in an array data that I have. It will return 1 and 0 if its exit or not. Inside my file is like this:
2j2H4F6d9d0d3hdfasgt.y7
But I cut the last 2 lines. And my array data is like this: [2w fr 5k 2j 0w]. I want to check whether my array data exist inside my file.
Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20
XX = 0
Set wshShell = CreateObject("WScript.Shell")
strFBString = wshShell.ExpandEnvironmentStrings("%FB%")
WScript.Echo "==>"
WScript.Echo "strFBString: " & strFBString
Set wshShell = Nothing
For i = 1 To Len(strFBString) Step 2
If StrComp(Mid(strFBString, i, 2), [2w fr 5k 2j 0w]) = 0 Then
XX = 1
End If
Next
WScript.Echo "XX: " & XX
WScript.Quit(XX)
For one thing, [2w fr 5k 2j 0w] is not a valid array definition in VBScript. If you want to define an array with these 5 string elements you need to do it like this:
Array("2w", "fr", "5k", "2j", "0w")
Also, StrComp() is for comparing a string to another string. It does not support comparing a string to an array. For comparing a string to each element of an array you need a loop. How to build that loop depends on the result you want to achieve, though.
Looking at your code it seems you want to find a match in 2j2H4..., but not in w2j2H..., so simply using InStr() probably won't work for you. In that case you could use an inner loop for the comparison:
ref = Array("2w", "fr", "5k", "2j", "0w")
For i = 1 To Len(strFBString) Step 2
For Each s In ref
If Mid(strFBString, i, 2) = s Then
'...
End If
Next
Next
But like I already said, details depend on the desired end result. If you want to check if your input string contains any of the array values you could do something like this:
ref = Array("2w", "fr", "5k", "2j", "0w")
found = False
For i = 1 To Len(strFBString) Step 2
For Each s In ref
If Mid(strFBString, i, 2) = s Then
found = True
Exit For
End If
Next
Next
If on the other hand you wanted to check if your input string contains all of the reference strings you'd probably do something like this instead:
ref = Array("2w", "fr", "5k", "2j", "0w")
For Each s In ref
found = False
For i = 1 To Len(strFBString) Step 2
If Mid(strFBString, i, 2) = s Then
found = True
Exit For
End If
Next
If Not found Then Exit For
Next
You could also use an entirely different approach, like putting your data in a dictionary:
data = CreateObject("Scripting.Dictionary")
For i = 1 To Len(strFBString) Step 2
data(Mid(strFBString, i, 2)) = True
Next
Using that approach you could check if the data contains any of the reference values like this:
found = False
For s In Array("2w", "fr", "5k", "2j", "0w")
If data.Exists(s) Then
found = True
Exit For
End If
Next
or check if the data contains all of the reference values like this:
found = True
For s In Array("2w", "fr", "5k", "2j", "0w")
If Not data.Exists(s) Then
found = False
Exit For
End If
Next

Validate text box input for numeric range 1-100

I am trying to validate inputs to accept only a range of numbers 1-100. I have it where it will accept numbers in the range from 1-100. What I need is how to make sure character inputs such as a letter or symbol (?,/,<,> ect...) can't be used. I am using a loop to look through each input that is put into an array. When inputs are validated I am returning a blnOk = True to use in my button event to run program. I have tried double.TryParse but I can't get it to work with the array. I also have Option Strict ON. dblStudentTestScores(i) is the array that the inputs are stored in. txtTestScores(i) array is being used to tell the program which text box the loop is on so that it can gain focus with an error.
Private Sub ValidateScores()
For i = 0 To 8
If dblStudentTestScores(i) >= 0 And dblStudentTestScores(i) <= 100 Then
blnOK = True
Else
MessageBox.Show("Please Enter Test Score between 0 and 100")
txtTestScores(i).Clear()
txtTestScores(i).Focus()
txtTestScores(i).BackColor = Color.Yellow
blnOK = False
Exit Sub
End If
txtTestScores(i).BackColor = Color.White
Next
blnOK = True
End Sub
This is the code with the IsNumeric but it won't go into the Else clause. It jumps into the try catch. I would really like it to gain focus on the textbox that has the invalid input. Like it does if the number is not between 0 and 100.
Private Sub ValidateScores()
For i = 0 To 8
If CInt(IsNumeric(dblStudentTestScores(i))) >= 0 And CInt(IsNumeric(dblStudentTestScores(i))) <= 100 Then
blnOK = True
Else
MessageBox.Show("Please Enter Test Score between 0 and 100")
txtTestScores(i).Clear()
txtTestScores(i).Focus()
txtTestScores(i).BackColor = Color.Yellow
blnOK = False
Exit Sub
End If
txtTestScores(i).BackColor = Color.White
Next
blnOK = True
End Sub
Each input populates the array.
Public Sub PopulateTestScores()
'Student 1 test scores
dblStudentTestScores(0) = CDbl(txtStudent1Score1.Text)
dblStudentTestScores(1) = CDbl(txtStudent1Score2.Text)
dblStudentTestScores(2) = CDbl(txtStudent1Score3.Text)
'Student 2 test scores
dblStudentTestScores(3) = CDbl(txtStudent2Score1.Text)
dblStudentTestScores(4) = CDbl(txtStudent2Score2.Text)
dblStudentTestScores(5) = CDbl(txtStudent2Score3.Text)
'Student 3 test scores
dblStudentTestScores(6) = CDbl(txtStudent3Score1.Text)
dblStudentTestScores(7) = CDbl(txtStudent3Score2.Text)
dblStudentTestScores(8) = CDbl(txtStudent3Score3.Text)
End Sub
You should use double.TryParse because, if the input is not a valid double, it returns false instead of throwing an exception.
Public Function PopulateTestScores() as Boolean
Dim ok as Boolean
ok = CheckInput(txtStudent1Score1.Text, 0)
if not ok Then
txtStudent1Score1.Focus()
return ok
End if
ok = CheckInput(txtStudent1Score2.Text, 1)
if not ok Then
txtStudent1Score2.Focus()
return ok
End if
.....
return ok
End Function
private Function CheckInput(input as String, index as integer) as Boolean
Dim d as Double
Dim ok as Boolean
ok = double.TryParse(input, d)
if ok Then dblStudentTestScores(index) = d
return ok
End Function
The version of TryParse with two arguments expects the string to be in the same format of your locale (point/comma for decimals). If you want to work with different cultures then just use the appropriate TryParse overload that takes also the CultureInfo parameter.
For example, if you use the overload that takes a NumberStyles and a CultureInfo
ok = Double.TryParse(input, NumberStyles.None, CultureInfo.CurrentCulture, d)
TryParse will return false if the input doesn't match your CultureInfo and the correct convention for digit grouping.
A valid double like 10.1 in en-US culture is invalid the it-IT one where the correct input is 10,1
you can check the input using the isNumeric function.
https://msdn.microsoft.com/en-us/library/6cd3f6w1(v=vs.90).aspx

rails 3.2 searching action. how to pass results to another action

I should create a search page in which i have to save in an Array all the results of the searching. I had two problems:
1) I used the following statement:
Company.joins(:references).where(sql_string)
that returns an ActiveRecord:Relation and it's not good for me cause i have to display these results in the index action , in which i use an each statement. So , to overcame this problem i used the to_a.
I checked the .class of my variable and with the to_a it passed from ActiveRecord:Relation to Array. So , it seems that this solve the problem.
Company.joins(:references).where(sql_string).to_a
2) Now, i have to pass this variable (Array) into my index action.
I executed the search in the action called search:
def search
...
#companies = Company.joins(:references).where(sql_string).to_a
end
Now, i want to pass this to index:
def index
#companies ||= Company.all
end
I used #companies ||= Company.all cause i think that the #companies is and istance variable and it should be available in all the actions of the class. Isn't it? By the way, it doesn't workl. I mean , the results are not shared through the two methods.
Also , in the search action i don't know how to call index action. I used the redirect_to but this bring me to another problem.
def search
...
#companies = Company.joins(:references).where(sql_string).to_a
redirect_to companies_index_path
end
The second time i call the search action it brings me into the index action.As i insered the searching value. At really he still had the past searching in memory, and i don't want this behavior.
So , in other words, i want to:
passing #companies searching result to index action.
avoid the loop between search-index. So in every new request resets
the old searching.
i want to know if it's correct the casting with the to_a to bring
an ActiveRecord:Relation to Array.
Thank You.
EDIT:
def search
stringa_sql = ""
ragione_sociale = ""
riferimento = ""
note = ""
min_date = ""
max_date = ""
company_type = ""
sector = ""
country = ""
certification = ""
contact = ""
state = ""
manage = ""
consultation = ""
formation = ""
software = ""
if params[:ragione_sociale]
ragione_sociale = params[:ragione_sociale]
stringa_sql = "ragione_sociale like "+"'%"+ragione_sociale+"%'"
end
if params[:riferimento]
riferimento = params[:riferimento]
stringa_sql += " AND nome like "+"'%"+riferimento+"%'"
end
if params[:note]
note = params[:note]
stringa_sql += " AND note like "+"'%"+note+"%'"
end
if params[:min_date] && params[:min_date]!= ""
if params[:max_date] && params[:max_date]!= ""
min_date = params[:min_date]
max_date = params[:max_date]
stringa_sql += " AND richiamare >="+min_date+" AND richiamare <="+max_date
end
end
if params[:company_type] #se inviamo la richesta senza scrivere params[:category] viene passato vuoto
if params[:company_type][:id] != ""
company_type = params[:company_type][:id]
stringa_sql += " AND id_forma_giuridica = "+company_type
end
end
if params[:sector]
if params[:sector][:id] != ""
sector = params[:sector][:id]
stringa_sql += " AND id_settore = "+sector
end
end
if params[:country]
if params[:country][:id] != ""
country = params[:country][:id]
stringa_sql += " AND id_provincia = "+country
end
end
if params[:certification]
if params[:certification][:id] != ""
certification = params[:certification][:id]
stringa_sql += " AND id_certificazione = "+certification
end
end
if params[:contact]
if params[:contact][:id] != ""
contact = params[:contact][:id]
stringa_sql += " AND id_contattato = "+contact
end
end
if params[:state]
if params[:state][:id] != ""
state = params[:state][:id]
stringa_sql += " AND id_stato = "+state
end
end
if params[:manage]
if params[:manage][:id] != ""
manage = params[:manage][:id]
stringa_sql += " AND id_gestito = "+manage
end
end
if params[:consultation]
if params[:consultation][:id] != ""
consultation = params[:consultation][:id]
stringa_sql += " AND id_consulenza = "+consultation
end
end
if params[:formation]
if params[:formation][:id] != ""
formation = params[:formation][:id]
#formazione DA METTERE
end
end
if params[:software]
if params[:software][:id] != ""
software = params[:software][:id]
stringa_sql += " AND id_software = "+software
end
end
#companies = Company.search(stringa_sql).to_a
if not #companies.empty?
redirect_to companies_index_path
end
end
index:
def index
#companies ||= Company.all
end
I used #companies ||= Company.all cause i think that the #companies
is and istance variable and it should be available in all the actions
of the class. Isn't it?
Not really, it depends on from where you want to access the #companies instance variable. e.g. from which view, you need #companies instance variable in the corresponding action method of the controller.
The second time i call the search action it brings me into the index
action
You are using redirect_to companies_index_path in your search method which brings you to the index action.
To implement search in your application, you can follow this somewhat standard process:
In your application_controller.rb which will have the #search_query.
# Returns string
def search_query
#search_query ||= params[:query] || params[:search]
end
Then, in your searches_controller.rb, you can have:
def search
# in the method build your search results based on
# search_query param
#search_results = Company.joins(:references).where(sql_string(search_query)).to_a
end
In your routes.rb, you can have:
get '/search(/:query)' => 'searches#search', query: /.+/, as: 'search'
Which will take you to the searches_controller's search action where you are building the search results #search_results.
Finally, you need to have a app/views/searches/search.html.erb view file where you have access to your #search_results instance variable and you can just loop through them and display them in this view.
Answers to your last 3 questions:
passing #companies searching result to index action.
avoid the loop between search-index. So in every new request resets
the old searching.
You can overcome these problems by following the request/response flow that I have mentioned above. You should not share your index view with your search and you should not have any loop between search and index. Both of them are separate actions of the controller and can be handled separately as I showed above.
i want to know if it's correct the casting with the to_a to bring an
ActiveRecord:Relation to Array.
You can do that if you want. But, you don't really need it in this use case. You can store the ActiveRecord:Relation in your search_results and when you access this instance variable from inside your search.html.erb view, you can easily loop through using a .each do block. So, you don't have to worry about ActiveRecord:Relation and Array.

Convert.ChangeType() Returns incorrect value

I've got a class that parses a CNC file, but I'm having difficulties with trailing "words" on each line of the file.
My code parses all leading "words" until it reaches the final word. It's most noticeable when parsing "Z" values or other Double type values. I've debugged it enough to notice that it successfully parses the numerical value just as it does with "X" and "Y" values, but it doesn't seem to successfully convert it to double. Is there an issue with a character I'm missing or something?
Here's my code:
If IO.File.Exists("Some GCode File.eia") Then
Dim sr As New IO.StreamReader("Some GCode File.eia")
Dim i As Integer = 0
'Read text file
Do While Not sr.EndOfStream
'Get the words in the line
Dim words() As String = sr.ReadLine.Split(" ")
'iterate through each word
For i = 0 To words.Length - 1 Step 1
'iterate through each "registered" keyword. Handled earlier in program
For Each cmd As String In _registeredCmds.Keys
'if current word resembles keyword then process
If words(i) Like cmd & "*" Then
_commands.Add(i, _registeredCmds(cmd))
'Double check availability of a Type to convert to
If Not IsNothing(_commands(i).DataType) Then
'Verify enum ScopeType exists
If Not IsNothing(_commands(i).Scope) Then
'If ScopeType is modal then just set it to True. I'll fix later
If _commands(i).Scope = ScopeType.Modal Then
_commands(i).DataValue = True
Else
'Catch errors in conversion
Try
'Get the value of the gcode command by removing the "registered" keyword from the string
Dim strTemp As String = words(i).Remove(0, words(i).IndexOf(_commands(i).Key) + _commands(i).Key.Length)
'Save the parsed value into an Object type in another class
_commands(i).DataValue = Convert.ChangeType(strTemp, _commands(i).DataType)
Catch ex As Exception
'Log(vbTab & "Error:" & ex.Message)
End Try
End If
Else
'Log(vbTab & "Command scope is null")
End If
Else
'Log(vbTab & "Command datatype is null")
End If
Continue For
End If
Next
Next
i += 1
Loop
Else
Throw New ApplicationException("FilePath provided does not exist! FilePath Provided:'Some GCode File.eia'")
End If
Here's an example of the GCode:
N2930 X-.2187 Y-1.2378 Z-.0135
N2940 X-.2195 Y-1.2434 Z-.0121
N2950 X-.2187 Y-1.249 Z-.0108
N2960 X-.2164 Y-1.2542 Z-.0096
N2970 X-.2125 Y-1.2585 Z-.0086
N2980 X-.207 Y-1.2613 Z-.0079
N2990 X-.2 Y-1.2624 Z-.0076
N3000 X0.
N3010 X12.
N3020 X24.
N3030 X24.2
N3040 X24.2072 Y-1.2635 Z-.0075
N3050 X24.2127 Y-1.2665 Z-.0071
N3060 X24.2167 Y-1.2709 Z-.0064
N3070 X24.2191 Y-1.2763 Z-.0057
N3080 X24.2199 Y-1.2821 Z-.0048
N3090 X24.2191 Y-1.2879 Z-.004
N3100 X24.2167 Y-1.2933 Z-.0032
N3110 X24.2127 Y-1.2977 Z-.0026
N3120 X24.2072 Y-1.3007 Z-.0021
N3130 X24.2 Y-1.3018 Z-.002
N3140 X24.
N3150 X12.
N3160 X0.
N3170 X-.2
N3180 X-.2074 Y-1.3029 Z-.0019
N3190 X-.2131 Y-1.306 Z-.0018
N3200 X-.2172 Y-1.3106 Z-.0016
N3210 X-.2196 Y-1.3161 Z-.0013
N3220 X-.2204 Y-1.3222 Z-.001
N3230 X-.2196 Y-1.3282 Z-.0007
N3240 X-.2172 Y-1.3338 Z-.0004
N3250 X-.2131 Y-1.3384 Z-.0002
N3260 X-.2074 Y-1.3415 Z-.0001
N3270 X-.2 Y-1.3426 Z0.
N3280 X0.
N3290 X12.
N3300 X24.
N3310 X24.2
N3320 G0 Z.1
N3330 Z1.0
N3340 G91 G28 Z0.0
N3350 G90
With regard to the sample CNC code above, you'll notice that X and Y commands with a trailing Z command parse correctly.
EDIT
Per comment, here is a breakdown of _commands()
_commands = SortedList(Of Integer, Command)
Command is a class with the following properties:
Scope as Enum ScopeType
Name as String
Key as String
DataType as Type
DataValue as Object
EDIT: Solution!
Figured out what was wrong. The arrays that make up the construction of the classes were essentially being passed a reference to the "registered" array of objects from the Command class. Therefore every time I parsed the value out of the "word" each line, I was overwriting the DataValue in the Command object.
The solution was to declare a new 'Command' object with every parse and append it to the proper array.
Here's my short hand:
...
For I = 0 To words.Length - 1 Step 1
'iterate through each "registered" keyword. Handled earlier in program
For Each cmd as String in _registeredCmds.Keys
'if current word resembles keyword then process
If words(I) Like cmd & "*" Then
'NEW!!! Declare unassigned Command object
Dim com As Command
' ****** New elongated logic double checking existence of values.....
If _registeredCmds.Keys.Scope = ScopeType.Modal Then
'assign Command object to previously declared variable com
com = New Command()'There's technically passing arguments now to ensure items are transferred
Else
'Parse and pass DataValue from this word
com = New Command()'There's technically passing arguments now to ensure items are transferred
End If
'New sub to add Command object to local array
Add(com)
Continue For
End If
Next
Next
...

Filtering a Cell Array with Recursion

I'm pretty close on this problem. What I have to do is filter out a cell array. The cell array can have a variety of items in it, but what I want to do is pull out the strings, using recursion. I am pretty close on this one. I just have an issue when the cells have spaces in them. This is what I should get:
Test Cases:
cA1 = {'This' {{{[1:5] true} {' '}} {'is '} false true} 'an example.'};
[filtered1] = stringFilter(cA1)
filtered1 => 'This is an example.'
cA2 = {{{{'I told '} 5:25 'her she'} {} [] [] ' knows'} '/take aim and reload'};
[filtered2] = stringFilter(cA2)
filtered2 => 'I told her she knows/take aim and reload'
Here is what I have:
%find the strings in the cArr and then concatenate them.
function [Str] = stringFilter(in)
Str = [];
for i = 1:length(in)
%The base case is a single cell
if length(in) == 1
Str = ischar(in{:,:});
%if the length>1 than go through each cell and find the strings.
else
str = stringFilter(in(1:end-1));
if ischar(in{i})
Str = [Str in{i}];
elseif iscell(in{i})
str1 = stringFilter(in{i}(1:end-1));
Str = [Str str1];
end
end
end
end
I tried to use 'ismember', but that didn't work. Any suggestions? My code outputs the following:
filtered1 => 'This an example.'
filtered2 => '/take aim and reload'
You can quite simplify your function to
function [Str] = stringFilter(in)
Str = [];
for i = 1:length(in)
if ischar(in{i})
Str = [Str in{i}];
elseif iscell(in{i})
str1 = stringFilter(in{i});
Str = [Str str1];
end
end
end
Just loop through all elements in the cell a test, whether it is a string or a cell. In the latter, call the function for this cell again. Output:
>> [filtered1] = stringFilter(cA1)
filtered1 =
This is an example.
>> [filtered2] = stringFilter(cA2)
filtered2 =
I told her she knows/take aim and reload
Here is a different implememntation
function str = stringFilter(in)
if ischar(in)
str = in;
elseif iscell(in) && ~isempty(in)
str = cell2mat(cellfun(#stringFilter, in(:)', 'uni', 0));
else
str = '';
end
end
If it's string, return it. If it is a cell apply the same function on all of the elements and concatenate them. Here I use in(:)' to make sure it is a row vector and then cell2mat concatenates resulting strings. And if the type is anything else return an empty string. We need to check if the cell array is empty or not because cell2mat({}) is of type double.
The line
Str = ischar(in{:,:});
is the problem. It doesn't make any sense to me.
You're close to the getting the answer, but made a few significant but small mistakes.
You need to check for these things:
1. Loop over the cells of the input.
2. For each cell, see if it itself is a cell, if so, call stringFilter on the cell's VALUE
3. if it is not a cell but is a character array, then use its VALUE as it is.
4. Otherwise if the cell VALUE contains a non character, the contribution of that cell to the output is '' (blank)
I think you made a mistake by not taking advantage of the difference between in(1) and in{1}.
Anyway, here's my version of the function. It works.
function [out] = stringFilter(in)
out = [];
for idx = 1:numel(in)
if iscell (in{idx})
% Contents of the cell is another cell array
tempOut = stringFilter(in{idx});
elseif ischar(in{idx})
% Contents are characters
tempOut = in{idx};
else
% Contents are not characters
tempOut = '';
end
% Concatenate the current output to the overall output
out = [out, tempOut];
end
end

Resources