VB.Net Extract numbers from string function - vb.net

My request is one that can extract a number somewhat by a search.
Example:
animalsOwned|4 would return an containing "4"
animals|3|2|1|3 would return an array containing "3", "2", "1", "3"
This would make it easier for me during a file stream reader.
Thank you

Dim astring = "ABCDE|1|2|3|4"
Dim numbers = (From s In astring
Where Char.IsDigit(s)
Select Int32.Parse(s)).ToArray()
This LINQ statement should help. It simply checks each character in a string to see if it's a digit. Note that this only applies to single digit numbers. It becomes a bit more complicated if you want "ABC123" to return 123 vs. 1, 2, 3 array.

Try regular expression. It's a powerful tool for simple text parsing.
Imports System.Text.RegularExpressions
Namespace Demo
Class Program
Shared Function Main(ByVal args As String()) As Integer
Dim array As Integer() = ExtractIntegers("animals|3|2|1|3")
For Each i In array
Console.WriteLine(i)
Next
Return 0
End Function
Shared Function ExtractIntegers(ByVal input As String) As Integer()
Dim pattern As String = "animals(\|(?<number>[0-9]+))*"
Dim match As Match = Regex.Match(input, pattern)
Dim list As New List(Of Integer)
If match.Success Then
For Each capture As Capture In match.Groups("number").Captures
list.Add(Integer.Parse(capture.Value))
Next
End If
Return list.ToArray()
End Function
End Class
End Namespace

I haven't programmed VB for awhile but I'll give you some pseudo code:
First, loop through each line of file. Call this variable Line.
Then, take the index of what you're searching for: like Line.indexOf("animalsOwned")
If it returns -1 it isn't there; continue.
Once you find it, add the Index variable to the length of the search string and 1. (Index=Index+1+Len(searchString))
Then, take a substring starting there, and end at the end of the line.
Explode the substring by | characters, then add each into an array.
Return the array.
Sorry that I can't give you much help, but I'm working on an important PHP website right now ;).

You can do a variable.Split("|") and then assign each piece to an array level.
You can do a count on string and with a while or for loop, you can assign the splited sections to array levels. Then you can do a IsNumeric() check for each array level.

Related

Is it possible to use String.Split() when NewLine is the delimiter?

I have a question which asks me to calculate something from an input file. The problem is, the lines in the file don't use any special character as delimiter, like , or |. I will show it down below.
Data Communication
20
Visual Basic
40
The output I need to write to another file should look like this:
Data communication 20
Visual Basic 40
Total Books : 60
The problem is, how can I specify the delimiter? Like when there is a symbol as in strArray = strLine.Split(","). Since there is nothing I can use as delimiter, how can I split the file content?
There's no real need to split the text in the input file, when you can read a file line by line using standard methods.
You can use, e.g., a StreamReader to read the lines from the source file, check whether the current line is just text or it can be converted to a number, using Integer.TryParse and excluding empty lines.
Here, when the line read is not numeric, it's added as a Key in a Dictionary(Of String, Integer), unless it already exists (to handle duplicate categories in the source file).
If the line represents a number, it's added to the Value corresponding to the category Key previously read, stored in a variable named previousLine.
This setup can handle initial empty lines, empty lines in the text body and duplicate categories, e.g.,
Data Communication
20
Visual Basic
40
C#
100
Visual Basic
10
Other stuff
2
C++
10000
Other stuff
1
If a number is instead found in the first line, it's treated as a category.
Add any other check to handle a different structure of the input file.
Imports System.IO
Imports System.Linq
Dim basePath = "[Path where the input file is stored]"
Dim booksDict = New Dictionary(Of String, Integer)
Dim currentValue As Integer = 0
Dim previousLine As String = String.Empty
Using sr As New StreamReader(Path.Combine(basePath, "Books.txt"))
While sr.Peek > -1
Dim line = sr.ReadLine().Trim()
If Not String.IsNullOrEmpty(line) Then
If Integer.TryParse(line, currentValue) AndAlso (Not String.IsNullOrEmpty(previousLine)) Then
booksDict(previousLine) += currentValue
Else
If Not booksDict.ContainsKey(line) Then
booksDict.Add(line, 0)
End If
End If
End If
previousLine = line
End While
End Using
Now, you have a Dictionary where the Keys represent categories and the related Value is the sum of all books in that category.
You can Select() each KeyValuePair of the Dictionary and transform it into a string that represents the Key and its Value (Category:Number).
Here, also OrderBy() is used, to order the categories alphabetically, in ascending order; it may be useful.
File.WriteAllLines is then called to store the strings generated.
In the end, a new string is appended to the file, using File.AppendAllText, to write the sum of all books in all categories. The Sum() method sums all the Values in the Dictionary.
Dim newFilePath = Path.Combine(basePath, "BooksNew.txt")
File.WriteAllLines(newFilePath, booksDict.
Select(Function(kvp) $"{kvp.Key}:{kvp.Value}").OrderBy(Function(s) s))
File.AppendAllText(newFilePath, vbCrLf & "Total Books: " & booksDict.Sum(Function(kvp) kvp.Value).ToString())
The output is:
C#:100
C++:10000
Data Communication:20
Other stuff:3
Visual Basic:50
Total Books: 10173
Sure.. System.IO.File.ReadAllLines() will read the whole file and split into an array based on newlines, so you'll get an array of 4 elements. You can process it with a flipflop boolean to get alternate lines, or you can try and parse the line to a number and if it works, then its a number and if not, it's a string. If it's a number take the string you remembered (using a variable) from the previous loop
Dim arr = File.ReadALlLines(...)
Dim isStr = True
Dim prevString = ""
For Each s as String in arr
If isStr Then
prevString = s
Else
Console.WriteLine($"The string is {prevString} and the number is {s}")
End If
'flip the boolean
isStr = Not isStr
Next s
I used File.ReadAllLines to get an array containing each line in the file. Since the size of the file could be larger than the sample shown, I am using a StringBuilder. This save having to throw away and create a new string on each iteration of the loop.
I am using interpolated strings indicated by the $ preceding the quotes. This allows you to insert variables into the string surrounded by braces.
Note the Step 2 in the For loop. i will increment by 2 instead of the default 1.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lines = File.ReadAllLines("input.txt")
Dim sb As New StringBuilder
Dim total As Integer
For i = 0 To lines.Length - 2 Step 2
sb.AppendLine($"{lines(i)} {lines(i + 1)}")
total += CInt(lines(i + 1))
Next
sb.AppendLine($"Total Books: {total}")
TextBox1.Text = sb.ToString
End Sub

visual studio split function issue

I try to call split function on visual studio as below and i expect it return me 2 item in array after split, but vb return 5 results from my coding. It is consider vb issue or my coding issue?
Whole string is "NAME":"ALICE"
Dim a As String = """NAME"":""ALICE"""
Dim b() As String = a.Split(""":")
Output I expected in array after split
(1) "NAME
(2) "ALICE"
You were using this overload of String.Split(Char[]). Note that takes an array of characters. String is convertible to an array of characters (and that's why you could compile) but it is not equal. Try putting Option Strict On at the top of your code. It won't compile as you have it anymore :)
When passing a single string, each character in the string is used to split. Including each " in your argument, ":. It will split on " and :. You can get around it by passing a string array to Split using this overload of String.Split(String[], SplitStringOptions). Pass a single element array like this
Dim b = a.Split({""":"}, StringSplitOptions.RemoveEmptyEntries)
Yes, that is exactly as you said,
"NAME
"ALICE"
Do you want to get rid of the quotes in the result? You can do this
Dim b = a.Split({":", """"}, StringSplitOptions.RemoveEmptyEntries)
Then it's this,
NAME
ALICE
Dim a As String = """NAME"":""ALICE"""
Dim b() As String = a.Split(":")
this is how it evaluates

Converting characters from Lower to upper case and vice versa VB.Net

had a search around and can't find an answer.
I've been tasked with converting a strings capitalization from whatever it is in Be it lower case or upper case and swap them round..
For Example :- Input :- "HeLlO" and Output :- "hElLo"
I understand that i need to use a for loop but have not been able to figure out how to step through each character, check the case and switch it if needs be.
I can make a for loop that counts through and displays the individual characters or a simple If statement to convert the whole string into Upper or lower but if i try to combine the 2 my logic isn't working right.
Can anyone help at all?
Here is one simple way to do it:
Public Function InvertCase(input As String) As String
Dim output As New StringBuilder()
For Each i As Char In input
If Char.IsLower(i) Then
output.Append(Char.ToUpper(i))
ElseIf Char.IsUpper(i) Then
output.Append(Char.ToLower(i))
Else
output.Append(i)
End If
Next
Return output.ToString()
End Function
It just loops through each character in the original string, checks to see what case it is, fixes it, and then appends that fixed character to a new string (via a StringBuilder object).
As Neolisk suggested in the comments below, you could make it cleaner by creating another method which converts a single character, like this:
Public Function InvertCase(input As Char) As Char
If Char.IsLower(input) Then Return Char.ToUpper(input)
If Char.IsUpper(input) Then Return Char.ToLower(input)
Return input
End Function
Public Function InvertCase(input As String) As String
Dim output As New StringBuilder()
For Each i As Char In input
output.Append(InvertCase(i))
Next
Return output.ToString()
End Function
Using that same function for InvertCase(Char), you could also use LINQ, like this:
Public Function InvertCase(input As String) As String
Return New String(input.Select(Function(i) InvertCase(i)).ToArray())
End Function
As a Linq query:
Dim input = "HeLlO"
Dim output = new String(input.Select(Function(c)
Return If(Char.IsLower(c),Char.ToUpper(c),Char.ToLower(c))
End Function).ToArray())
Console.WriteLine(output)
Honestly, who writes loops these days? :-)

Creating Newlines in PDF with VB.net

I have an application which creates a list from items in a collection. Then for each item, I will add it to an empty string, then add a newline character to the end of it. So ideally my string will look something like:
List1\nList2\nList3\n
Once this string is generated, I send it back to be placed in a placeholder for a pdf. If I try this code in a simple console application, it prints everything on a newline. But in my real world situation, I have to print it to a pdf. The items only show up with spaces in between them and not newlines. How can can format my strings so that pdf recognizes the newline symbol rather than ignoring it?
Here is my code that generates the string with newlines.
Private Function ConcatPlacardNumbers(ByVal BusinessPlacardCollection As BusinessPlacardCollection) As String
Dim PlacardNumbersList As String = Nothing
Dim numberofBusinessPlacards As Long = BusinessPlacardCollection.LongCount()
For Each BusinessPlacard As BusinessPlacard In BusinessPlacardCollection
numberofBusinessPlacards = numberofBusinessPlacards - 1
PlacardNumbersList = String.Concat(PlacardNumbersList, BusinessPlacard.PlacardNumber)
If numberofBusinessPlacards <> 0 Then
PlacardNumbersList = String.Concat(PlacardNumbersList, Enviornment.newline)
End If
Next
Return PlacardNumbersList
End Function
Try to add \u2028 instead:
Private Function ConcatPlacardNumbers(ByVal BusinessPlacardCollection As _
BusinessPlacardCollection) As String
Dim PlacardNumbersList As New StringBuilder()
For Each BusinessPlacard As BusinessPlacard In BusinessPlacardCollection
PlacardNumbersList.Append(BusinessPlacard.PlacardNumber)
'PlacardNumbersList.Append(ChrW(8232)) '\u2028 line in decimal form
PlacardNumbersList.Append(ChrW(8233)) '\u2029 paragr. in decimal form
Next
Return PlacardNumbersList.ToString
End Function
For paragraphs use \u2029instead. Fore more details:
http://blogs.adobe.com/formfeed/2009/01/paragraph_breaks_in_plain_text.html
The answer will depend on the tool that is being used to produce the PDF. Since newline doesn't work, I would actually try \n. The other possibility is that the PDF generation code is not designed to emit multiple lines; you can only determine this by examining the generation code.
However, there is a significant performance issue that you should address in your code: you will be generating a lot of string objects using this code. You should change the design to use System.Text.StringBuilder, which will greatly improve the performance:
Private Function ConcatPlacardNumbers(ByVal BusinessPlacardCollection As BusinessPlacardCollection) As String
Dim PlacardNumbersList As New System.Text.StringBuilder(10000)
For Each BusinessPlacard As BusinessPlacard In BusinessPlacardCollection
If PlacardNumbersList.Length <> 0 Then
' This is equivalent to Environment.NewLine
'PlacardNumbersList.AppendLine()
' The attempt to use \n
PlacardNumbersList.Append("\n")
End If
PlacardNumbersList.Append(BusinessPlacard.PlacardNumber)
Next
Return PlacardNumbersList.ToString
End Function
Note that you also do not need to keep track of the placard number: you can add a newline to the end of the previous item on each pass after the first one.

To check if array consist of only elements from another array, VB.NET

Working with a Visual Basic.NET console application that features a VERY BASIC natural language recognition function-it only has to work with specific fields of words so it wasn't that hard. I got the logic all lay out on paper, but I've encountered a problem.
I want the application to check if the user input is only consist of valid words.
When the user inputs something, I used a function to cut it down to only alphanumeric characters, and used the string.split method to create an array that contains separate words the user input. What I wish to do now is to compare the input array to another array (a full set of valid words), and return an error message if the input array contains only elements that exist in the valid words array.
For instance, if all valid words are "ALPHA", "BETA" and "GAMMA".
When the use inputs something like "ALPHA BETA"-the program will accept the input.
If the input is "APPLES" then it will return an error message because the string APPLE is not a member of the valid words array.
I hope I've made my question clear enough, anyone please help. Thanks.
Maybe you are looking for something like the All()-Method, which checks if each element in a collection satisfies a condition. Consider the following example:
Dim validWords = {"ALPHA", "BETA", "GAMMA"}
Dim thisIsNotValid = {"ALPHA", "APPLES"}.All(Function(word) validWords.Contains(word))
Dim thisIsValid = {"ALPHA", "BETA"}.All(Function(word) validWords.Contains(word))
thisIsNotValid will evaluate to False, and thisIsValid will evaluate to True.
I'd use Except, http://msdn.microsoft.com/en-us/library/bb300779.aspx
Private AllowedWords As String() = {"these", "are", "good", "words"}
Sub Main()
Dim badUserInput As String() = {"these", "are", "bad", "words"}
Dim badWords As IEnumerable(Of String) = badUserInput.Except(AllowedWords)
If badWords.Any Then
' User has entered a disallowed word
Throw New ArgumentException(String.Format("Words '{0}' are not allowed", String.Join(",", badWords)))
End If
End Sub
I also wrote a blog on different ways to join collections a while ago:
http://dotnetrene.blogspot.co.uk/2012/01/joining-collections-in-linq-contains-vs.html
You could use a HashSet(T) to store your allowed words. HashSet.Contains is an O(1) operation rather than an O(n) found in other collections, which makes a HashSet(T) more efficient.
Private Shared AllowedWords As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase) From
{
"Alpha", "Beta", "Gamma"
}
Public Shared Function WordsAreValid(ParamArray words() As String) As Boolean
For Each word As String In words
If Not AllowedWords.Contains(word) Then Return False
Next
Return True
End Function
In your case, it is not necessary to use array as data structure. Instead, you can store your list of valid words in System.Collections.Specialized.NameValueCollection class. Then, you can test each user input against the list of valid words that stored in System.Collections.Specialized.NameValueCollection class.
How to store valid word in System.Collections.Specialized.NameValueCollection class:
See this.
How to check if there is valid word entry in System.Collections.Specialized.NameValueCollection class: See this