Searching for a word and not a string? - string

I want to check a file for a particular word the way I have found posted on various forums is to use the following code...
Dim content = My.Computer.FileSystem.ReadAllText(filePath)
If content.Contains("stringToSearch") Then
'Do your stuff
End If
Which is okay until you discover that it will search and match compound words and the likes. For instance If I search for the string light in a file and it's not there but instead the word lightning is, it will still register as having found a match... Is there a way to find and exact word using VB.net?

As mentioned by Andrew Morton, Regex makes this kind of thing very easy. For instance, if you made a function like this:
Public Function ContainsWord(input As String, word As String) As Boolean
Return Regex.IsMatch(input, $"\b{word}\b")
End Function
You could use it like this:
Dim content = My.Computer.FileSystem.ReadAllText(filePath)
If ContainsWord(content, "stringToSearch") Then
'Do your stuff
End If
If you wanted to, you could even make it an extension method on the String type, by putting it in a Module and adding the ExtensionAttribute, like this:
<Extension>
Private Function ContainsWord(input As String, word As String) As Boolean
Return Regex.IsMatch(input, $"\b{word}\b")
End Function
And then you could call it like this:
Dim content = My.Computer.FileSystem.ReadAllText(filePath)
If content.ContainsWord("stringToSearch") Then
'Do your stuff
End If

Another method, using Regex.Matches, which allows to search for a collection of words and returns a Dictionary(Of String, Integer()).
The Dictionary Key represent the matched word, the Value, as an Array of Integers, all the positions inside the File where the word was found.
The extension method requires 2 parameters:
- the path of the file to search
- a boolean value, used to specify whether the search should be case sensitive.
Proposed as an extension method of IEnumerable(Of String):
Dim fileName As String = "[File Path]"
Dim searchWords As String() = {"light", "lighting", "clip", "clipper", "somethingelse"}
Dim result = searchWords.FindWords(fileName, False)
Print a result of the matches found:
result.ToList().ForEach(
Sub(w)
Console.WriteLine($"Word: {w.Key} Positions: {String.Join(", ", w.Value)}")
End Sub)
Extension method:
Imports System.IO
Imports System.Runtime.CompilerServices
Imports System.Text
Imports System.Text.RegularExpressions
Module modIEnumerableExtensions
<Extension()>
Public Function FindWords(words As IEnumerable(Of String),
fileName As String,
caseSentive As Boolean) As Dictionary(Of String, Integer())
Dim pattern As StringBuilder = New StringBuilder()
pattern.Append(String.Concat(words.Select(Function(w) $"\b{w}\b|")))
Dim options As RegexOptions = RegexOptions.Compiled Or
If(caseSentive, RegexOptions.Multiline, RegexOptions.IgnoreCase Or RegexOptions.Multiline)
Dim regx As New Regex(pattern.ToString().TrimEnd("|"c), options)
Dim matches As MatchCollection = regx.Matches(File.ReadAllText(fileName))
Dim groups = matches.OfType(Of Match).
GroupBy(Function(g) g.Value).
ToDictionary(Function(g) g.Key, Function(g) g.Select(Function(m) m.Index).ToArray())
Return groups
End Function
End Module

The shortest and fastest way to do this is using ReadLines with LINQ queries, specialy when you are working with a large files.
Dim myword As String = "Book"
Dim reg = New Regex("\b" & myword & "\b", RegexOptions.IgnoreCase)
Dim res = From line In File.ReadLines(largeFileName)
Where reg.IsMatch(line)
If your file containts "Book", "Books", "Book." and "Book," the results will be:
Book
Book,
Book.
And you can working with results as following
TextBox1.Text = resLines.Count
Or
TextBox1.Text = resLines(0)
Edited to make it consering "." and "," etc.

Related

Get string after second delimiter VB NET

I am trying to get the part of the string after the second /.
For instance if I have the string "25/S17/874"
I would like to get "874"
Thanks
you can split the string by "/" and the call back from the array.
Example:
Dim string_sample As String
Dim string_arr As String()
string_sample = "25/S17/874"
string_arr = string_sample.Split("/")
Dim string_Result As String
string_Result = string_arr(2)
MsgBox(string_Result)
the string_Result is "874"
Dim result As String = "25/S17/874".Split("/"c)(2)
Obviously, some validation, error trapping, etc might be required if the string content is prone to variation.

Indent a string by 4 spaces (Add Tab to string)

I am trying to add indentation to a string, essentially adding 4 spaces in front of each line in the string. The string that I want to add the indentation to is called StringToIndent.
Public Class ModifyPage
Private Sub Button_Test_Click(sender As Object, e As RoutedEventArgs) Handles Button_Test.Click
Dim StringToIndent As String = ("This is the first row
This is the second row
This is the third and final row in MyString")
Dim MySecondString As String = "This is a string in one line."
Dim BothStringsTogether = StringToIndent & Environment.NewLine & MySecondString
Debug.Write(BothStringsTogether)
End Sub
End Class
The current output:
This is the first row
This is the second row
This is the third and final row in MyString
This is a string in one line.
I want the final code (that is indented) to output:
This is the first row
This is the second row
This is the third and final row in MyString
This is a string in one line.
How can this be achieved through code? Is there a formatting option that allows me to add indentation? A method that doesn't require me to loop through a string and adding four spaces for each line would be preferable.
Edit: A way to achieve the expected output is to replace the new line with a new line and then add the indent. However, there must be a more elegant way of doing it?
Code:
Dim StringToIndent As String = ("This is the first row
This is the second row
This is the third and final row in MyString")
Dim indentAmount = 4
Dim indent = New String(" "c, indentAmount)
StringToIndent = indent & StringToIndent.Replace(Environment.NewLine, Environment.NewLine & indent)
Debug.Write(StringToIndent)
Maybe something like:
Dim res as String
Dim parts As String() = StringToIndent.Split(ControlChars.CrLf.ToCharArray)
For Each part As String In parts
res.Append(" ") & part & vbCrLf
Next
In C# you can mark the String as a verbatim string literal by prefixing the literal with the # symbol.
In VB.NET we don't have this option. Instead, a workaround would be to create an XML literal and get the value. Here is an example:
Dim input As String = <element> This is the first row
This is the second row
This is the third and final row in MyString
This is a string in one line.
</element>.Value().ToString()
Debugger.WriteLine(input.ToString())
If the value is not static, e.g. you're getting it from somewhere, then you're forced to iterate through the String in some form. You can either Replace like in your example, do a Split and Join (similar to your example), or you'll need to manually iterate.
The manual iteration could look more elegant using LINQ, but you don't gain anything from it.
The bottom line is that if your String is static then you can use the XML literal example I provided, otherwise if the String is dynamic then your solution is perfectly appropriate.
UPDATE
As Andrew Morton pointed out, multiple line String literals have existed since Visual Studio 2017. The following would produce the same outcome as my XML literal example:
Dim input As String = " This is the first row
This is the second row
This is a string in one line"
Debugger.WriteLine(input)
Using an interpolated string indicated by the $ preceeding the string and the vb constants.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim s = $"{vbTab}This Is the first row{vbCrLf}{vbTab}This Is the second row{vbCrLf}{vbTab}{vbTab}This Is the third And final row in MyString{vbCrLf}This Is a string in one line."
Debug.Print(s)
End Sub

how to format many emails with regex using vba

With vba, i want to validate many emails between then with semicolon,every mail must end with #customercurrency.com and user can put 2 or 3 or 4 or many emails as he want.
Example : aung#customercurrency.com;thet#customercurrency.com;htoo#customercurrency.com
My code is here.But it might be something wrong.
Public Function ValidateEmailAddressWithSemi(ByRef strEmailAddress As String) As Boolean
'Create Regular expression object
Dim objRegExp As New RegExp
'Set Case insensitive
objRegExp.IgnoreCase = True
objRegExp.pattern = "^\s?([_a-z0-9-]+(.[a-z0-9-]+)#customconcurrency.com)+([;.]([_a-z0-9-]+(.[a-z0-9-]+)#customconcurrency.com)*$"
ValidateEmailAddress = objRegExp.Test(strEmailAddress)
End Function
try this pattern :
"^\s?([_a-z0-9-]+(.[a-z0-9-]+)#customercurrency.com)+([;.]([_a-z0-9-]+(.[a-z0-9-]+)#customercurrency.com))*$"
(mistake in the domain name and a paranthesis is missing)

How do I search an online document for specific string and it's value?

Example, Online document: [removed link as no longer needed]
Which outputs:
Value1=1
Value2=5
The rest of this document would have random text to ignore.
I would like to search for Value1 and Value2, then output it's value [I need this to be expandable if I decide to add new information in the future]
[the output may be longer than one character, and might be text rather than a number]
Dim Value1Result as Integer = [value from online file] '1 in this case
Dim Value2Result as Integer = [value from online file] '5 in this case
Edit: Added logic to strip the version number. Very basic but as long as the format doesn't change it should work. You'll need to handle parsing to int, double, etc if you ever use "1.2" or whatever for a version.
If I understand your question correctly, you just need to download the file, store it in a local variable, and then do something with it. Comment if this is not the case and I will adjust.
I would do this by creating a WebClient, downloading the data, converting it to a string, and then operating on it. I did not add any headers - dropbox doesn't require it, but something to keep in mind for production... Small example below:
Dim bResult() As Byte
Dim sUrl As String = "https://dl.dropboxusercontent.com/s/bus2q71wsn9txuz/Test.txt?dl=0"
Using client As New WebClient
bResult = client.DownloadData(sUrl)
End Using
Dim retData As String = Encoding.UTF8.GetString(bResult)
Dim retList As List(Of String) = retData.Split(Environment.NewLine).ToList()
Dim sMin = retList(0).Split("=").Last()
Dim sNew = retList(1).Split("=").Last()

Resharper or CodeRush - global rename

Is there a way to rename all methods, properties etc. suggested by R#. I have code that I converted from java and all methods and properties are in the format like this "onBeforeInsertExpression" and I want them to follow camel casing that is common in .NET.
This question is also for CodeRush.
I needed the same functionality and couldn't find it. I considered writing an add-in to ReSharper using the Api but decided on a regular Visual Studio macro instead. This macro renames methods and private fields in the current document to the default ReSharper settings, but can easily be modified to iterate through all files in a project or solution.
Save this code as a .vb file and import it into your VS Macros.
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports EnvDTE90a
Imports EnvDTE100
Imports System.Diagnostics
Public Module RenameMembers
Enum NamingStyle
UpperCamelCase
LowerCamelCase
End Enum
Public Sub RenameMembers()
Try
'Iterate through all code elements in the open document
IterateCodeElements(ActiveDocument.ProjectItem.FileCodeModel.CodeElements)
Catch ex As System.Exception
End Try
End Sub
'Iterate through all the code elements in the provided element
Private Sub IterateCodeElements(ByVal colCodeElements As CodeElements)
Dim objCodeElement As EnvDTE.CodeElement
If Not (colCodeElements Is Nothing) Then
For Each objCodeElement In colCodeElements
Try
Dim element As CodeElement2 = CType(objCodeElement, CodeElement2)
If element.Kind = vsCMElement.vsCMElementVariable Then
RenameField(element)
ElseIf element.Kind = vsCMElement.vsCMElementFunction Then
'Rename the methods
ApplyNamingStyle(element, NamingStyle.UpperCamelCase)
ElseIf TypeOf objCodeElement Is EnvDTE.CodeNamespace Then
Dim objCodeNamespace = CType(objCodeElement, EnvDTE.CodeNamespace)
IterateCodeElements(objCodeNamespace.Members)
ElseIf TypeOf objCodeElement Is EnvDTE.CodeClass Then
Dim objCodeClass = CType(objCodeElement, EnvDTE.CodeClass)
IterateCodeElements(objCodeClass.Members)
End If
Catch
End Try
Next
End If
End Sub
'Rename the field members according to our code specifications
Private Sub RenameField(ByRef element As CodeElement2)
If element.Kind = vsCMElement.vsCMElementVariable Then
Dim field As EnvDTE.CodeVariable = CType(element, EnvDTE.CodeVariable)
If (field.Access = vsCMAccess.vsCMAccessPrivate) Then
'private static readonly
If (field.IsShared AndAlso field.IsConstant) Then
ApplyNamingStyle(element, NamingStyle.UpperCamelCase)
ElseIf (Not field.IsShared) Then
'private field (readonly but not static)
ApplyNamingStyle(element, NamingStyle.LowerCamelCase, "_")
Else
ApplyNamingStyle(element, NamingStyle.UpperCamelCase)
End If
Else
'if is public, the first letter should be made uppercase
ToUpperCamelCase(element)
End If
'if public or protected field, start with uppercase
End If
End Sub
Private Function ApplyNamingStyle(ByRef element As CodeElement2, ByVal style As NamingStyle, Optional ByVal prefix As String = "", Optional ByVal suffix As String = "")
Dim the_string As String = element.Name
If (Not the_string Is Nothing AndAlso the_string.Length > 2) Then
If (style = NamingStyle.LowerCamelCase) Then
ToLowerCamelCase(the_string)
ElseIf (style = NamingStyle.UpperCamelCase) Then
ToUpperCamelCase(the_string)
Else
'add additional styles here
End If
End If
AddPrefixOrSuffix(the_string, prefix, suffix)
If (Not element.Name.Equals(the_string)) Then
element.RenameSymbol(the_string)
End If
End Function
Private Function ToLowerCamelCase(ByRef the_string As String)
the_string = the_string.Substring(0, 1).ToLower() & the_string.Substring(1)
End Function
Private Function AddPrefixOrSuffix(ByRef the_string As String, Optional ByVal prefix As String = "", Optional ByVal suffix As String = "")
If (Not the_string.StartsWith(prefix)) Then
the_string = prefix + the_string
End If
If (Not the_string.EndsWith(suffix)) Then
the_string = the_string + suffix
End If
End Function
Private Function ToUpperCamelCase(ByRef the_string As String)
the_string = the_string.Substring(0, 1).ToUpper() & the_string.Substring(1)
End Function
End Module
No, unfortunately there isn't a way. Resharper's Code Cleanup / Reformat Code options work nicely for formatting, namepaces, etc, but will not do any automatic member renaming. You're kinda stuck doing a "Quick Fix" on each member. If you have a lot of them, this can be a pain...
CodeRush's approach to this kind of fix is more of an interactive process.
Which is to say you have to physically be in the location of the variable whose name you wish to change and you have to change each one individually.
That said, there is a very powerful engine under CodeRush called the DXCore, which can be used to create a very wide variety of functionality. Indeed it is this layer on which the whole of CodeRush and RefactoPro are built.
I have no doubt that it could be used to create the functionality you are after. However I doubt that you would use the existing rename technology. I will have to look into this a little further, but I am optimistic about being able to produce something.

Resources