How to make string.contains work with a list - vb.net

So I have this bot I'm making for someone that filters out curse words in a skype chat.
Instead of making it so my code is really long I want it so there is a huge list of curse words already loaded for example:
If Msg.Contains("swear1") Or Msg.Contains("swear2") Then
c.SendMessage("{---------Bot----------}" + vbNewLine + "DO NOT SWEAR!" + vbNewLine + "{-------------------------------------------}")
End If
I've tried creating an array and a string holding multiple values and didn't really work out too good as it didn't execute the function after someone said the trigger word. So I wanted to know if there is a way I can hold a huge list of curse words in one whatever without using
Msg.Contains("swear1")
Or
Msg.Contains("swear2")
etc etc, so everything would be held in one bit.
Any help would be appreciated :)

You use a Collection of Swear words and check the string against that. The .Any method takes the array and internally creates a For/loop with the word being the variable name for this loop and represents each string in the the array to test with our SwearWords.Contains(word) boolean expression, and if any of the expressions equates to True then it returns True.
Dim swearWordExists As Boolean = False
Dim msg As String = "swear1! has a swear word with extra text but still found"
Dim SwearWords As New List(Of String)
' fill it with your swear words
SwearWords.AddRange(New String() {"swear1", "swear2", "etc..."})
' then
If Not msg.Contains(" ") Then
' msg only has one word so check it
If SwearWords.Contains(msg) OrElse SwearWords.Any(Function(words) msg.Contains(words)) Then
swearWordExists = True
End If
Else
Dim words = Regex.Split(msg, "\W")
If Not words.Any(Function(word) SwearWords.Contains(word)) Then
If words.Any(Function(word) SwearWords.Any(Function(swear) word.Contains(swear))) Then
swearWordExists = True
End If
Else
swearWordExists = True
End If
End If
If swearWordExists Then
MessageBox.Show("Why are you swearing?")
End If

An easy but not super performant way would be to convert your string to a list then use the list intersect functionality
http://msdn.microsoft.com/en-us/library/vstudio/bb910215(v=vs.90).aspx

You could condense your code like this
Dim swears = New List(Of [String])() From {"swear1", "swear2"}
If Regex.IsMatch("[your message]", String.Format("({0})", String.Join("|", swears))) Then
MsgBox("Don't swear!")
End If
Where swears would be your list of all swears you don't want someone to say
What it does is it takes all strings in 'swears' and puts them into this format: (swear1|swear2) then regex will see if your message contains either 'swear1' or 'swear2' et cetera if you have more.

Related

Best way to loop through a list within a sub-loop

First things first, I did a search before posting this question but the answers are so generic that I could not find anything similar to what I'm trying to do. I apologize in advance if this has been answered before and I did not find it.
I have a scenario where I already collected a large list of rows (>10K) from the SQL server and put into an array (List) of strings. These rows are consisted of filenames. Because I already put them on a list, I don't want to query the SQL server again and instead want work with what I already have in memory.
This is the code I'm trying to get right:
'Valid file types for InfoLink1, InfoLink2, InfoLink3
Dim lstValidImageFormats As New List(Of String)({".JPG", ".JPEG", ".JPE", ".BMP", ".PNG", ".TIF", ".TIFF", ".GIF"})
Dim lstValidSTLFormats As New List(Of String)({".STL"})
Dim lstValidSTEPFormats As New List(Of String)({".STP", ".STEP"})
'////////////////
'// Components //
'////////////////
'We don't check Parts.InfoLink because all formats are allowed in this field
'Parts.InfoLink1 - File in Infolink1 columns MUST BE images
For i = 0 To arrStrComponentsInfolink1Values.Count - 1 'We have 10K rows with filenames in this list
For Each FileExtension As String In lstValidImageFormats
If arrStrComponentsInfolink1Values.Item(i).EndsWith(FileExtension) = False Then
End If
Next
Next
I'm trying to parse each item (filename) I have in the array arrStrComponentsInfolink1Values and check if the filename DOES NOT end with one of the extensions in the list lstValidImageFormats. If it doesn't, then I'll send the filename to another list (array).
My difficulty here is about how to iterate through each item in arrStrComponentsInfolink1Values, then check if each filename ends with one of the extensions declared in lstValidImageFormats, do what I want to do with the item if it DOES NOT end with one of those extensions, and then proceed to parse the next item in arrStrComponentsInfolink1Values.
I sincerely don't know what's the best way/performance efficient to do that.
My code above is empty because algorithmically I don't know the best approach to do what I want without querying the SQL server again with something like AND filename NOT LIKE '%.JPG' AND filename NOT LIKE '%.JPEG' AND filename NOT LIKE '%.JPE' AND filename NOT LIKE '%.BMP'...
Because I already have the data in the memory in a list, performance would be much better if I could use what I already have.
Any suggestions or material I could read to learn how to do what I'm looking for?
Thank you!
Here's how I would tackle this:
Dim invalidFormatFiles = _
From x In arrStrComponentsInfolink1Values _
Let fi = New FileInfo(x) _
Where Not lstValidImageFormats.Contains(fi.Extension.ToUpperInvariant()) _
Select x
For Each invalidFormatFile In invalidFormatFiles
' Do your processing
Next
I ended up doing this and it worked:
Dim lstValidImageFormats As New List(Of String)({".JPG", ".JPEG", ".JPE", ".BMP", ".PNG", ".TIF", ".TIFF", ".GIF"})
Dim lstValidSTLFormats As New List(Of String)({".STL"})
Dim lstValidSTEPFormats As New List(Of String)({".STP", ".STEP"})
'////////////////
'// Components //
'////////////////
'We don't check Parts.InfoLink because all formats are allowed in this field
'Parts.InfoLink1 - File in Infolink1 columns MUST BE images
Dim intExtCounter As Integer = 0
For i = 0 To arrIntComponentsInfolink1UNRs.Count - 1 'We have 10K rows with filenames in this list
intExtCounter = 0
For j = 0 To lstValidImageFormats.Count - 1
If arrStrComponentsInfolink1Values.Item(i).EndsWith(lstValidImageFormats.Item(j)) = True Then
intExtCounter += 1
End If
Next
If intExtCounter = 0 Then 'At least one file extension was found
arrIntComponentsInfolink1UNRsReportSectionInvalidExtensions.Add(i) 'File extension is not in the list of allowed extensions
End If
Next
But #41686d6564 answer was the best solution:
Dim newList = arrStrComponentsInfolink1Values.Where(Function(x) Not lstValidImageFormats.Contains(IO.Path.GetExtension(x))).ToList()
Thank you!

Lowercase the first word

Does anybody know how to lowercase the first word for each line in a textbox?
Not the first letter, the first word.
I tried like this but it doesn't work:
For Each iz As String In txtCode.Text.Substring(0, txtCode.Text.IndexOf(" "))
iz = LCase(iz)
Next
When you call Substring, it is making a copy of that portion of the string and returning it as a new string object. So, even if you were successfully changing the value of that returned sub-string, it still would not change the original string in the Text property.
However, strings in .NET are immutable reference-types, so when you set iz = ... all you are doing is re-assigning the iz variable to point to yet another new string object. When you set iz, you aren't even touching the value of that copied sub-string to which it previously pointed.
In order to change the value of the text box, you must actually assign a new string value to its Text property, like this:
txtCode.Text = "the new value"
Since that is the case, I would recommend building a new string, using a StringBuilder object, and then, once the modified string is complete, then set the text box's Text property to that new string, for instance:
Dim builder As New StringBuilder()
For Each line As String In txtCode.Text.Split({Environment.NewLine}, StringSplitOptions.None)
' Fix case and append line to builder
Next
txtCode.Text = builder.ToString()
The solutions here are interesting but they are ignoring a fundamental tool of .NET: regular expressions. The solution can be written in one expression:
Dim result = Regex.Replace(txtCode.Text, "^\w+",
Function (match) match.Value.ToLower(), RegexOptions.Multiline)
(This requires the import System.Text.RegularExpressions.)
This solution is likely more efficient than all the other solutions here (It’s definitely more efficient than most), and it’s less code, thus less chance of a bug and easier to understand and to maintain.
The problem with your code is that you are running the loop only on each character of the first word in the whole TextBox text.
This code is looping over each line and takes the first word:
For Each line As String In txtCode.Text.Split(Environment.NewLine)
line = line.Trim().ToLower()
If line.IndexOf(" ") > 0 Then
line = line.Substring(0, line.IndexOf(" ")).Trim()
End If
// do something with 'line' here
Next
Loop through each of the lines of the textbox, splitting all of the words in the line, making sure to .ToLower() the first word:
Dim strResults As String = String.Empty
For Each strLine As String In IO.File.ReadAllText("C:\Test\StackFlow.txt").Split(ControlChars.NewLine)
Dim lstWords As List(Of String) = strLine.Split(" ").ToList()
If Not lstWords Is Nothing Then
strResults += lstWords(0).ToLower()
If lstWords.Count > 1 Then
For intCursor As Integer = 1 To (lstWords.Count - 1)
strResults += " " & lstWords(intCursor)
Next
End If
End If
Next
I used your ideas guys and i made it up to it like this:
For Each line As String In txtCode.Text.Split(Environment.NewLine)
Dim abc() As String = line.Split(" ")
txtCode.Text = txtCode.Text.Replace(abc(0), LCase(abc(0)))
Next
It works like this. Thank you all.

Count instances of specific string in Email

I've looked for similar questions regarding this with no luck. I currently have working code that looks for a specific instance of string in the email body and subject. Upon finding this string, it has userform that takes it in another direction. My intentions are to have it run through the entire email and count how many times it finds this iteration and give that a callable variable for that userform(popup). Here is my code. It comes back with an error that says "InvalidCastException" so i'm guessing this is a conversion error. Any ideas? Thanks!
Ok so I added your comments together and came up with the following. I'm getting alot of errors, as the regex.Pattern I'm assuming doesn't exist. Any ideas? Also thank you for the literature.
Dim regEx ' Create variable.
Dim numfound As Integer
regEx = New RegExp ' Create a regular expression.
'Here it tells me that the regEx.Patter doesn't exist or Pattern is a member of the regex class
regEx.Pattern = "\*#{9}\*" ' Set pattern.
regEx.IgnoreCase = True ' Set case insensitivity.
regEx.Global = True ' Set global applicability.
If regEx.Execute(mailItem.Body) Then
' Getting a "not declared" runtime what should it be declared a Integer such as Dim numfound as Object
numfound = regEx.count
End If
Did some more digging and basically I'm back where I started with an InvalidCastException,
Conversion from string "111111111
123121233
" to type 'Long' is not valid.
Basically in the body of my test email I had those two strings of numbers and it can't convert them to a string to then run through the regexp iteration. Any ideas?
Dim sBody : sBody = (mailItem.Body) Or (mailItem.Subject) 'This is where is gives me the error
Dim Search : Search = New RegExp
Search.Global = True
Search.Pattern = "\*#{9}\*"
MsgBox(Search.Execute(sBody).Count, MsgBoxStyle.OkOnly)
To get you started, if you want to use a RegExp:
(1) Start your reading here and here
(2) Demo code to give you food for thought:
>> Dim sBody : sBody = "Three instances of ###: ### and a part of ####."
>> Dim Search : Set Search = New RegExp
>> Search.Global = True
>> Search.Pattern = "#{3,3}"
>> WScript.Echo Search.Execute(sBody).Count
>>
3
>>
The easiest way to do this would be just create an instance of RegEx and use it to parse the Item.Body.
Set Search = new RegExp
Search.IgnoreCase = True
Search.Global = True
Search.Pattern = "\*#{9}\*"
If Search.Test(Item.Body) Then
'will hold how many times it has been found
numFound = Search.Count
End If
Here is a link with a bit more information on RegExp http://msdn.microsoft.com/en-us/library/ms974570.aspx

VB.NET Get text in between Quotations or other symbols

I want to be able to extract a string in between quotation marks or parenthesis etc. to a variable. For example my text might be "Hello there "Bob" ". I want to extract the text "Bob" from in between the two quotation marks and put it in the string "name" for later use. The same would be for "Hello there (Bob)". How would I go about this? Thanks.
=======EDIT======
Sorry, I worded this poorly. Ok, so lets say I have a textbox(Textbox1) and a button. If the user inputs the text: MsgBox "THIS IS MY MESSAGE" I want that when the Button is pressed, only the text THIS IS MY MESSAGE is displayed.
This is a solution very simple:
Dim sAux() As String = TextBox1.Text.Split(""""c)
Dim sResult As String = ""
If sAux.Length = 3 Then
sResult = sAux(1)
Else
' Error or something (number of quotes <> 2)
End If
There are basically three methods -- regular expressions, string.indexof and substring and finally looping over the characters one by one. I would avoid the latter as it is just reinventing the wheel. Whether to use regexs or indexof depends upon the complexity of your requirements and data. Indexof is a bit wordy but fairly straightforward and possibly just what you want in this case.
Dim str as String = "Hello there ""Bob"""
Dim startName as Integer
Dim endName as Integer
Dim name as String = ""
startName = str.IndexOf("""")
endName = str.Indexof("""", If(startName > 0, startName,0))
If (endName>startName) Then
name = str.SubString(startName, endName)
End If
If you need to do this for arbitrary symbols, then you want regexs.

vb.net - Search textfile from certain string, read from that point

this is probably not that hard to do.
But I've got two text files. The first has got a list of certain keywords.
Each one if these keywords are fed into a combobox.
Now, when I choose one of the items from this combobox, I want to search the other textfile for the same keyword and read from that point to the next keyword. And then feed each line into a listbox. Hope I make myself understood.
Perhaps I should use an INI-file for this purpose, doesn't really matter for me.
The textfiles have this structure;
Textfile1:
London
Oslo
New York
Hamburg
Amsterdam
The second textfile has this structure;
Textfile2:
'London'
Apples
Oranges
Pears
'Oslo'
Pasta
Salami
Monkeyballs
'New York'
Dada
Duda
Dadadish
Etc etc.
Is this possible? The reason I want to do it this way is to create a fully dynamic system. One which relies fully on whatever information is stored in these textfiles. I'm gonna build pretty complex strings from these results later on.
So far, I've got this to read the first file and add each line to the combobox:
Dim oReadMenuFunction as System.IO.StreamReader
oReadMenuFunction = IO.File.OpenText("textfile1.txt")
Do While oReadMenuFunction.Peek <> -1
Dim LineIn as String = oReadMenuFunction.ReadLine()
Combobox.Items.Add(LineIn)
Loop
Here's a sample function you could use to parse your second file. It takes a keyword as argument and returns the associated items:
Function ReadData(ByRef keyword As String) As IEnumerable(Of String)
Dim result = New List(Of String)
Using reader = New StreamReader("file2.txt")
Dim line As String = reader.ReadLine()
Dim take = False
Do While line IsNot Nothing
If line.StartsWith("'") Then
take = False
End If
If String.Equals("'" + keyword + "'", line) Then
take = True
End If
If take And Not String.IsNullOrEmpty(line) And Not line.StartsWith("'") Then
result.Add(line)
End If
line = reader.ReadLine()
Loop
End Using
Return result
End Function
And you use it like this:
Dim items = ReadData("London")