Loop through contents in the text file - vb.net

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)

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

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

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:

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.

vb.net Line numbering in multi line Rich Text Box if line starts with specific condition

Let me start by saying that I'm new to any language of coding besides G-code, and I've researched this until my fingers hurt. I've actually been working on this project for a little over a year now on my own, and this is the first hurdle I haven't been able to find my way around.
I'm creating an editor for cnc G-code, and i'm trying to add a Re-number function to it. I'm using a multi line richtextbox to display the the G-code to the user. I'm trying to edit each line of code that starts with the character "N", and if a line doesn't start with that character then it's left alone.
I figured the best way to do this would be to loop thru the RTB and pass each line into an array. Then I could use an If statement to see if a cell in the array started with the char "N" or in my case "blockLetter". Then use the replace function to correct the line Number.
This is what I have so far.
Dim increment As Integer = txtLNIncrement.Text
Dim blockLetter As String = txtLNStartTxt.Text
Dim count As Integer = 0
Dim block As Integer = count + increment
For Each cell As String In frmNC.NcTextBox.Lines
If cell.StartsWith(blockLetter) Then
Dim newCell As String = cell.Replace(blockLetter, block)
block = block + increment
MessageBox.Show(newCell)
End If
Next
Example of G-code that needs to be renumbered:
N50 M01
N60 T0101 (TOOL NAME)
N70 M41
N80 G96 S350
N90 M03
N100 M08
This is what I want:
N10 M01
N20 T0101 (TOOL NAME)
N30 M41
N40 G96 S350
N50 M03
N60 M08
This is what I'm getting when I run the code above:
1050 M01
2060 T0101 (TOOL NAME)
3070 M41
4080 G96 S350
5090 M03
60100 M08
I believe my issue is that the cell.replace is splitting each cell at the "N" character, and dropping it all together. Thus adding what I want to see in front of the existing numbers, minus the "N" character. How can I overwrite the existing block number to the correct ascending block number, and retain the "N" character? Am I going about this in the correct way, or is there a better way? Any help is greatly appreciated.
Try something like this out:
Private increment As Integer = 10
Private blockLetter As String = "N"
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim newLine As String
Dim values() As String
Dim lineNumber As Integer = 0
Dim lines As New List(Of String)(NcTextBox.Lines)
For i As Integer = 0 To lines.Count - 1
If lines(i).TrimStart().StartsWith(blockLetter) Then
values = lines(i).TrimStart(" " & blockLetter.ToCharArray).Split(" ")
lineNumber = lineNumber + increment
values(0) = lineNumber
newLine = blockLetter & String.Join(" ", values)
lines(i) = newLine
End If
Next
NcTextBox.Lines = lines.ToArray
End Sub
it's very simple:
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim blockLetter As String = "N"
Dim increment As Integer = 1
For i As Integer = 0 To RichTextBox1.Lines.Length - 1 Step 1
Dim fullLine As String = RichTextBox1.Lines(i)
If fullLine.StartsWith(blockLetter) Then
Dim numbering As String = fullLine.Remove(RichTextBox1.Lines(i).IndexOf(" "))
Dim block As Integer = numbering.Substring(1)
Dim newCell As String = blockLetter & block + increment
MessageBox.Show(newCell)
End If
Next
End Sub
Result:
The Label1.Text will increase with button click.
It's all about Substring() starting from index 1 after 'N', so you will get the number.
Good luck with your coding!

Load specific data from text and put into datagridview

I'm a new programmer and I'm trying to create a small program that will help me finish many things.
How it's looks like?
This is how the text file's data is formatted:
**;======================= Start**
(item (name 256) (Index 1) (Image "Wea001") (Action 1 1) (class
weapon sword) (code 1 1 1 1) (country 2) (level 1) (wear
1) (limit Knight 1) (range 16) (buy 4) (sell 1) (endurance
4) (specialty (aspeed 700) (Attack 3 10) (hit 15) ) )
**;======================== end**
I need to import the (number beside the name), the (number beside the index), and the (name beside the Image).
User will be loading the text file from an open file dialog and the 3 columns will display the 3 fields that I am asking for help with.
Can anybody show me example of code to load text file data, into a datagridview? I am using vb.net
Here's a way that uses the existing format. This uses a datatable to contain the data then it's used as the datasource for the datagridview It searches for the correct line, then splits the line by the closing parenthesis ), then extracts the data by splitting each piece by the space.
Imports System.IO
Public Class Form1
Dim dt As New DataTable
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim sr As New StreamReader("InitItem.txt")
Dim DataString As String = ""
Dim ImageIndex As Integer = 2
dt.Columns.AddRange({New DataColumn("Name"), New DataColumn("Index"), New DataColumn("Image")})
While Not sr.EndOfStream
DataString = sr.ReadLine
If DataString.Contains("(item") Then
Dim ParseData() As String = DataString.Split(")"c)
If (ParseData(ImageIndex).Contains("desc")) Then
ImageIndex = 3
End If
AddNewRow(ParseData, ImageIndex)
End If
End While
DataGridView1.DataSource = dt
End Sub
Private Sub AddNewRow(ParseData() As String, ImageIndex As Integer)
Dim TempRow As DataRow = dt.NewRow
TempRow.ItemArray = {ParseData(0).Trim.Split({" "c}, StringSplitOptions.RemoveEmptyEntries)(1), _
ParseData(1).Trim.Split({" "c}, StringSplitOptions.RemoveEmptyEntries)(1), _
ParseData(ImageIndex).Trim.Split({" "c}, StringSplitOptions.RemoveEmptyEntries)(1).Trim(""""c)}
dt.Rows.Add(TempRow)
End Sub
End Class
Splitting by the ) ensures that when we want to extract the data after we split by the space, that the string doesn't have the ) tacked on to the end.
Because the text file format is kind of all over the place I made this code specifically for the data you requested. If you want something more generic then, as already mentioned, you should consider a more standard format for the file. Since there doesn't seem to be a lot of data, I would suggest a field/value pair on each line.