Visual_basic : How to get single letters and letterstrings of 2 and 3 consecutive letters in the same label after clicking button? - vb.net

Trying to make a Windows app with Visual basic (2015) for my kids to help them in their reading process.
Made 3 labels (Box1, Box2, Box3) that can contain 1 letter each, but also 2 or 3 letterstrings (like "ea" "ou", "tr", "str"...).
And a label with clickfunction, so the predefined letters change randomly, with each click, in each box.
I managed to get individual predefined single letters in the boxes, but can't find a way to get 2 consecutive letters in those boxes.
Anyone can help me.
Examples of outcome:
consonants vowels consonants
m a p => map
m a rs => mars
m ea n => mean
m ee t => meet
spr i ng => spring
My VB-code uptill now is:
Public Class VLLK1_2
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim rand As New Random
Dim letter As String = "gkmnprstv "
Dim consonant As String = "gkmnprts "
Dim vowel As String = "aei"
letter = letter.Substring(rand.Next(letter.Length), 1)
Box1.Text = letter
vowel = vowel.Substring(rand.Next(vowel.Length), 1)
Box2.Text = vowel
consonant = consonant.Substring(rand.Next(consonant.Length), 1)
Box3.Text = consonant
End Sub
End Class

Im no word expert but wouldnt it be easier like the coment just mentioned to create List(of String) containing words that you want to learn. Then select randomly each word and divide it into 3 parts and add those parts into your textboxes?
Private rand As New Random
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
Dim ListW As New List(Of String)
ListW.Add("apple")
ListW.Add("pinaple")
ListW.Add("pen")
ListW.Add("orange")
ListW.Add("water")
'select random word from list
Dim randW As String = ListW(rand.Next(0, ListW.Count - 1))
'Dim randW = "pinaple"
'find the integer divider value
Dim div As Integer = randW.Length / 3
'divide the word into 3 parts
Dim leftP As String = Strings.Left(randW, div)
Dim midP As String = Strings.Left(Strings.Mid(randW, div + 1), div)
Dim reminderLenght = randW.Length - (leftP.Length + midP.Length)
Dim rightP As String = Strings.Right(randW, reminderLenght)
'now add the parts to text boxes
tb1.Text = leftP
tb2.Text = midP
tb3.Text = rightP
End Sub
End Class
Preview:

Related

How to use Nested Loop in Visual Basic for all unrepeated combinations of characters?

I am trying to get the combinations of all possible unrepeated character sets from the user input.
As I am just beginning to learn the programming, it is obvious that I don't properly understand how those nested loops work.
Here is my code:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ListBox1.Items.Clear()
Dim c1 As String = TextBox1.Text
Dim i, j As Integer
Dim str As String()
Dim k As Integer = 0
For i = 0 To c1.Length - 1
For j = 0 To i
ListBox1.Items.Add(c1(i) & c1(j))
Next
Next
End Sub
End Class
As you can see in the picture attached, I cannot get the rest. How can I get the character pairs I put in the red box on notepad?
Can someone help me, please.enter image description here
You had the right idea. However, expand your logic so that for every letter of the outer loop you spin through every letter again. And if you don't want repeated letter pairs, add an If statement:
For i = 0 To c1.Length - 1
For j = 0 To c1.Length - 1
If i <> j Then ListBox1.Items.Add(c1(i) & c1(j))
Next
Next

create 1000, 8-character random ID's, all unique and display in a text box

enter image description hereWrite a program to display 1000 8-character random user IDs in a text box after you click a button. Make sure the program verifies that none of the IDs are identical. Each userid should include a mixture of alphabetic characters and numbers.
What I have so far, which could be enough to get by as a random ID generator alone, but it does not loop 1000 times to be displayed in the label, and doesn't check for repeated ID's.
Public Class Form1
Private Sub btnGenerateRandomID_Click(sender As Object, e As EventArgs) Handles btnGenerateRandomID.Click
Dim rand As New Random
Dim char1 As String
Dim char2 As String
Dim char3 As String
Dim char4 As String
Dim char5 As String
Dim char6 As String
Dim char7 As String
Dim char8 As String
char1 = ChrW(rand.Next(Asc("A"), Asc("Z") + 1))
char2 = ChrW(rand.Next(Asc("A"), Asc("Z") + 1))
char3 = ChrW(rand.Next(Asc("A"), Asc("Z") + 1))
char4 = ChrW(rand.Next(Asc("A"), Asc("Z") + 1))
char5 = rand.Next(0, 9)
char6 = rand.Next(0, 9)
char7 = rand.Next(0, 9)
char8 = rand.Next(0, 9)
lblRandomId.Text = char1 + char2 + char3 + char4 + char5 + char6 + char7 + char8
End Sub
End Class
Thanks.
EDIT:
Public Class Form1
'Write a program to display 1000 8-character random user IDs in a text
'box after you click a button. Make sure the program verifies that none Of the IDs are identical.
'Each userid should include a mixture Of alphabetic characters And numbers.
Private Sub btnGenerateRandomID_Click(sender As Object, e As EventArgs) Handles btnGenerateRandomID.Click
Dim strChar As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
Dim rand As New Random
Dim strID As String = ""
For count_ids As Integer = 0 To 999
For count_chars As Integer = 0 To 7
strID += strChar(rand.Next(0, 62))
Next count_chars
lblRandomId.Text = strID
Next
End Sub
End Class
Here is the actual question "Q. Write a program to display 1000 8-character random user IDs in a text box after you click a button. Make sure the program verifies that none of the IDs are identical. Each userid should include a mixture of alphabetic characters and numbers.
Explain your program in your essay, with screenshots. Include a paragraph on the random number generator used in Visual Basic, and answer the question: how should the random number generator be best seeded?"
First of all, Welcome to StackOverflow,
From what i understand from your post you want to generate 1000 8 Character long Unique ID's
First of all we declare our variables
Dim Characters As String = "AZERTYUIOPQSDFGHJKLMWXCVBN0123456789" 'Declare All Characters on one string
Dim IDsList As New List(Of String) With {.Capacity = 1000} 'You can limit the capacity to 1000
Dim Id As String = ""
Dim Rand As New Random
Now we begin to genearte ID's and add them to IDsList using a nested loop
For i As Integer = 0 To 999 'This is a Zero Based Index so 999 is actually 1000
For _i As Integer = 0 To 7 'This also means 7 is 8
Id += Characters(Rand.Next(0, 36))
Next
IDsList.Add(Id)
Id = ""
Next
'You can Check for duplicates by adding this piece of code or use the next one instead
Dim NoDupesIDsList As New List(Of String)
NoDupesIDsList = IDsList.Distinct.ToList
For i As Integer = 0 To 999 'This is a Zero Based Index so 999 is actually 1000
For _i As Integer = 0 To 7 'This also means 7 is 8
Id += Characters(Rand.Next(0, 36))
Next
If not IDsList.contains(Id) then
IDsList.Add(Id)
End if
Id = ""
Next
Use a Textbox with multiline and scroll bar for better experience
Feel free to ask me anything via comments
PS: I tested my method and it's working , enjoy it !
This function will return the ASCII characters between 48 an 122. That will include some characters that are not letters or numbers but this makes the ids even more unique and simplifies the code.
The For loop builds the ids with a length of 8. Then the id is checked for uniqueness with the .Contains method. Only if it is not in the list, it is added to the list and the counter is incremented.
Private Rnd As New Random
Private Function GetListOfIDs() As List(Of String)
Dim Counter As Integer
Dim lst As New List(Of String)
Dim id As String = ""
Do While Counter < 1000
id = ""
For i = 0 To 7
id &= Chr(Rnd.Next(48, 123))
Next
If Not lst.Contains(id) Then
lst.Add(id)
Counter += 1
End If
Loop
Return lst
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lst = GetListOfIDs()
TextBox1.Text = String.Join(vbCrLf, lst)
End Sub
EDIT
As per suggestion by Caius Jard in comments I have added a solution using a HashSet. Same idea only a HashSet will not accept duplicate entries. The .Add method returns a boolean telling you if the Add was successful.
Private Function GetListOfIDs() As HashSet(Of String)
Dim hs As New HashSet(Of String)
Dim id As String = ""
Do While hs.Count < 1001
id = ""
For i = 0 To 7
id &= Chr(Rnd.Next(48, 123))
Next
If hs.Add(id) Then
Counter += 1
End If
Loop
Return hs
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim hs = BuildHashSet()
TextBox1.Text = String.Join(vbCrLf, hs)
End Sub
This method is probably more efficient because a HashSet is designed for hight performance. For 1000 items I did not notice any difference in the user interface. The text box updated immediately with both methods.
This will create the names:
Function RandomName(length As Integer) As String
Shared rnd As New Random()
Shared corpus() As Char = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray()
Return New String(Enumerable.Range(0, length).Select(Function(c) corpus(rnd.Next(corpus.Length))).ToArray())
End Function
Iterator Function GetUniqueNames(length As Integer, count As Integer) As IEnumerable(Of String)
Dim names As New HashSet(Of String)
For i As Integer = 0 To count
Dim name As String = RandomName(length)
While names.Contains(name)
'Potential (but unlikely) halting problem
name = RandomName(length)
End While
names.Add(name)
Yield name
Next
End Function
Dim uniqueNames = GetUniqueNames(8, 1000)
But do you really want to display 1000 of them in a single label?
lblRandomId.Text = string.Join(vbCrLf, uniqueNames)
Let's talk about your code.
Dim strChar As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
This assignment will work in your loop because a String is really an array of Char. This is why you can refer to an index in the string.
Dim rand As New Random()
The .net Random class provides a seed for Random based on system time. Only rarely would you want to provide a seed.
From the docs https://learn.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1
CONSTRUCTORS
Random() Initializes a new instance of the Random class
using a default seed value.
Random(Int32) Initializes a new instance of the Random class, using
the specified seed value.
For count_ids As Integer = 0 To 999
A For loop is not appropriate for this problem. We only want to increment the counter if we get a unique ID. The above For loop will increment on every iteration.
Do While Counter < 1000
'Code here
Loop
Notice in my code the counter is only incremented if the ID is unique.
The following loop should work fine but above this code we need to reset strID to an empty string. Otherwise we will have a very long string.
For count_chars As Integer = 0 To 7
strID += strChar(rand.Next(0, 62))
Next count_chars
You should not update the user interface (the label) on each iteration of the loop. Repainting the screen is one of the slowest operations in code. This line will overwrite the string in the label on every iteration.
lblRandomId.Text = strID
Move the update of the UI to after both loops are complete
Your code never checks for duplicates.
Now let's fix it.
We use a List(Of T) to accumulate the IDs. The T stands for Type; in our case it is String. A List is like an array only you don't have to know ahead of time how many entries there will be. No ReDim Preserve required.
Moved Dim strID As String = "" to the beginning of the inner loop so we will get a new strID on each iteration of the outer loop.
Changed strID &= strChar(rand.Next(0, 62)). &= instead of +=. In VB.net we use the ampersand to concatenate strings although the plus sign will work. The .Next method of the Random class has an overload that takes 2 Integers. It is inclusive of the first and exclusive of the second which means (0, 62) will return numbers form 0 to 61. Your string with a length of 62 has indexes of 0 to 61.
Next we check for duplicates with the .Contains method of the List class. This method does just what you would expect. We pass the new ID to the method and it returns a Boolean telling if the string is already in the list.
If it is not in the list, we add it to the list and increment the counter. The counter is only incremented if we have a successful add.
Finally we update the user interface by using a method of the String class. the .Join method takes a separator and the list to join. The TextBox must be multiline and have scroll bars.
I changed the names of the controls so I could test it in my testing program.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lst As New List(Of String)
Dim strChar As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
Dim rand As New Random()
Dim counter As Integer
Do While counter < 1000
Dim strID As String = ""
For count_chars = 0 To 7
strID &= strChar(rand.Next(0, 62))
Next
If Not lst.Contains(strID) Then
lst.Add(strID)
counter += 1
End If
Loop
TextBox1.Text = String.Join(vbCrLf, lst)
End Sub
EDIT
The official documentation for this method can be found here.
https://learn.microsoft.com/en-us/dotnet/api/system.string.join?view=netcore-3.1
I know it will be difficult to read but just take a look. Eventually you will be able to understand it and will be using these docs a lot.
String.Join(separator, List(Of String))
The separator is what to put between the strings in the list. In our case that is vbCrLf which is a vb constant for new line. Cr = Carraiage Return and Lf = Line Feed. Other types of collections that contain strings can also use this method.
The method takes each string in the list and adds the separator. After it is done with the list it returns one long string which we display in the TextBox.

Loop through contents in the text file

New TechGuy on this site. Thought i'd make this resourceful since im getting ready to graduate and want more programming practice. I have a question:
I tried looping through a text file I created and I wanted to replace each multiple of 3 with the word "changed". I created a text file and entered numbers 1-15 on each line. My code is below but for some reason it would only change the number 3 and 13. I tried using this link as a resource (Loop through the lines of a text file in VB.NET) but that wasnt to helpful. Anyway here is my code, can someone help with what i'm doing wrong?
Public Class numbers
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim OpenFilePrompt As New OpenFileDialog
openFilePrompt.ShowDialog()
Dim currentReader As New System.IO.StreamReader(OpenFilePrompt.FileName)
txtInput.Text = currentReader.ReadToEnd
Dim a As String
Dim numbers As New List(Of String)
a = txtInput.Text
numbers.Add(a)
Dim b As Integer
For i = 0 To numbers.Count Step 3
b = b + 3
TextBox2.Text = (numbers.Item(i).Replace(b.ToString, "Changed"))
Next
End Sub
End Class
You are setting numbers (the first item) to a, which is txtInput.Text.
Then you have a one size list which is completely useless!
You should use Mod instead.
Divides two numbers and returns only the remainder.
So just check if Integer Mod 3 equals 0.
Also consider using File.ReadAllLines(String), Val(String), String.Join(String, String()) and File.WriteAllLines(String, String()).
Dim Content() As String = File.ReadAllLines(OpenFilePrompt.FileName)
For Index As Integer = 0 To Content.Length - 1
Dim Number As Integer = Val(Content(Index))
If Number Mod 3 = 0 Then
Content(Index) = "changed"
End If
Next
txtInput.Text = String.Join(vbCrLf, Content)
File.WriteAllLines(OpenFilePrompt.FileName, Content)

Using Functions in Visual Basic

The program I'm working on has two different functions, one that calculates the number of syllables in a text file, and another that calculates the readability of the text file based on the formula
206.835-85.6*(Number of Syllables/Number of Words)-1.015*(Number of Words/Number of Sentences)
Here are the problems I'm having:
I'm supposed to display the contents of the text file in a multi-line text box.
I'm supposed to display the answer I get from the function indexCalculation in a label below the text box.
I'm having trouble calling the function to actually have the program calculate the answer to be displayed in the label.
Here is the code I have so far.
Option Strict On
Imports System.IO
Public Class Form1
Private Sub ExitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ExitToolStripMenuItem.Click
Me.Close()
End Sub
Private Sub OpenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OpenToolStripMenuItem.Click
Dim open As New OpenFileDialog
open.Filter = "text files |project7.txt|All file |*.*"
open.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
If open.ShowDialog() = Windows.Forms.DialogResult.OK Then
Dim selectedFileName As String = System.IO.Path.GetFileName(open.FileName)
If selectedFileName.ToLower = "project7.txt" Then
Dim text As String = File.ReadAllText("Project7.txt")
Dim words = text.Split(" "c)
Dim wordCount As Integer = words.Length
Dim separators As Char() = {"."c, "!"c, "?"c, ":"c}
Dim sentences = text.Split(separators, StringSplitOptions.RemoveEmptyEntries)
Dim sentenceCount As Integer = sentences.Length
Dim vowelCount As Integer = 0
For Each word As String In words
vowelCount += CountSyllables(word)
Next
vowelCount = CountSyllables(text)
Label1.Show(indexCalculation(wordCount, sentenceCount, vowelCount))
Else
MessageBox.Show("You cannot use that file!")
End If
End If
End Sub
Function CountSyllables(word As String) As Integer
word = word.ToLower()
Dim dipthongs = {"oo", "ou", "ie", "oi", "ea", "ee", _
"eu", "ai", "ua", "ue", "au", "io"}
For Each dipthong In dipthongs
word = word.Replace(dipthong, dipthong(0))
Next
Dim vowels = "aeiou"
Dim vowelCount = 0
For Each c In word
If vowels.IndexOf(c) >= 0 Then vowelCount += 1
Next
If vowelCount = 0 Then
vowelCount = 1
End If
Return vowelCount
End Function
Function indexCalculation(ByRef wordCount As Integer, ByRef sentenceCount As Integer, ByRef vowelCount As Integer) As Integer
Dim answer As Integer = CInt(206.835 - 85.6 * (vowelCount / wordCount) - 1.015 * (wordCount / sentenceCount))
Return answer
End Function
End Class
Any suggestions would be greatly appreciated.
Here are my suggestions:
update your indexCalculation function to take in Integers, not strings. that way you don't have to convert them to numbers.
remove all of your extra variables you are not using. this will clean things up a bit.
remove your streamreader. it appears you are reading the text via File.ReadAllText
Label1.Show(answer) should be changed to Label1.Show(indexCalculation(wordCount,sentenceCount,vowelCount)) -- unless Label1 is something other than a regular label, use Label1.Text = indexCalculation(wordCount,sentenceCount,vowelCount))
Then for the vowelCount, you need to do the following:
Dim vowelCount as Integer = 0
For Each word as String in words
vowelCount += CountSyllables(word)
Next
Also, add the logic to the CountSyllables function to make it 1 if 0. If you don't want to include the last character in your vowel counting, then use a for loop instead of a for each loop and stop 1 character short.

how to extract certain text from string

How do I filter/extract strings?
I have converted a PDF file into String using itextsharp and I have the text displayed into a Richtextbox1.
However there are too many irrelevant text that I don't need in the Richtextbox.
Is there a way I can display the text I want based on keywords, the entire length of the text.
Example of text that is displayed in textrichbox1 after conversation of PDF to text:
**774**
**Bos00232940
Bos00320491
Das1234
Das3216**
RAGE*
So the keywords would be "Bos", "Das", "774". and the new text that would be displayed in the richtextbox1 is shown below, instead of the entire text above.
*Bos00232940
Bos00320491
Das1234
Das3216
774*
Here is what I have so far. But it doesn't work it still displays the entire PDF in the richtextbox.
Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim pdffilename As String
pdffilename = TextBox1.Text
Dim filepath = "c:\temp\" & TextBox1.Text & ".pdf"
Dim thetext As String
thetext = GetTextFromPDF(filepath)
Dim lines() As String = System.Text.RegularExpressions.Regex.Split(thetext, Environment.NewLine)
Dim keywords As New List(Of String)
keywords.Add("Bos")
keywords.Add("Das")
keywords.Add("774")
Dim newTextLines As New List(Of String)
For Each line As String In lines
For Each keyw As String In thetext
If line.Contains(keyw) Then
newTextLines.Add(line)
Exit For
End If
Next
Next
RichTextBox1.Text = String.Join(Environment.NewLine, newTextLines.ToArray)
End Sub
SOLUTION
Thanks everyone for your help. Below is the code that worked and did exactly what I wanted it to do.
Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim pdffilename As String
pdffilename = TextBox1.Text
Dim filepath = "c:\temp\" & TextBox1.Text & ".pdf"
Dim thetext As String
thetext = GetTextFromPDF(filepath)
Dim re As New Regex("[\t ](?<w>((774)|(Bos)|(Das))[a-z0-9]*)[\t ]", RegexOptions.ExplicitCapture Or RegexOptions.IgnoreCase Or RegexOptions.Compiled)
Dim Lines() As String = {thetext}
Dim words As New List(Of String)
For Each s As String In Lines
Dim mc As MatchCollection = re.Matches(s)
For Each m As Match In mc
words.Add(m.Groups("w").Value)
Next
Next
RichTextBox1.Text = String.Join(Environment.NewLine, words.ToArray)
End Sub
For Each Word As String In thetext.Split(" ")
For Each key As String In keywords
If Word.StartsWith(key) Then
newTextLines.Add(Word)
Continue For
End If
Next
Next
or using LINQ:
Dim q = From word In thetext.Split(" ")
Where keywords.Any(Function(s) word.StartsWith(s))
Select word
RichTextBox1.Text = String.Join(Environment.NewLine, q.ToArray())
If don't know the keywords in advance but know in which context they occur, you can find them with a Regex expression. Two very handy Regex expressions allow you to find occurences succeeding or preceeding another:
(?<=prefix)find finds a pattern that follows another.
find(?=suffix) finds a pattern that comes before another.
If your number keyword (774) always preceeds " SIZE" you can find it like this: \w+(?=\sSIZE).
If the other keywords are always between "EX " and " DETAILS" you can find them like this: (?<=EX\s)(\w+\s)+(?=DETAILS).
You can put the whole thing together like this: \w+(?=\sSIZE)|(?<=EX\s)(\w+\s)+(?=DETAILS).
The disadvantage is that the keywords between "EX " and "DETAILS" will be returned as one match. But you can split the matches afterwards as in:
Const input As String = "2 3 3 4 4 A A B B SHEET 1 OF 1 774 SIZE SCALE 24.000-47.999 12.000-23.999 CON BAG WIRE 90in. EX Bos00232940 Bos00320491 Das1234 Das3216 DETAILS 1 2 RAGE"
Dim matches = Regex.Matches(input, "\w+(?=\sSIZE)|(?<=EX\s)(\w+\s)+(?=DETAILS)")
For Each m As Match In matches
Dim words = m.Value.Split(" "c)
For Each word As String In words
If word.Length > 0 Then ' Suppress the last empty word.
Console.WriteLine(word)
End If
Next
Next
Output:
774
Bos00232940
Bos00320491
Das1234
Das3216
How to do it with regular expression...
Dim re As New Regex("[\t ](?<w>((774)|(Bos)|(Das))[a-z0-9]*)[\t ]", RegexOptions.ExplicitCapture Or RegexOptions.IgnoreCase Or RegexOptions.Compiled)
Private Sub test()
Dim Lines() As String = {"2 3 3 4 4 A A B B SHEET 1 OF 1 774 SIZE SCALE 24.000-47.999 12.000-23.999 CON BAG WIRE 90in. EX Bos00232940 Bos00320491 Das1234 Das3216 DETAILS 1 2 RAGE"}
Dim words As New List(Of String)
For Each s As String In Lines
Dim mc As MatchCollection = re.Matches(s)
For Each m As Match In mc
words.Add(m.Groups("w").Value)
Next
Next
End Sub
Regex break down...
[\t ] Single tab or space (there is an alternative for whitespace too)
(?<w> Start of capture group called "w" This the the text returned later in the "m.Groups"
((774)|(Bos)|(Das)) one of the 3 blobs of text
[a-z0-9]* any a-z or 0-9 character, * = any number of them
) End of Capture group "w" from above.