Reading from text files in Visual Basic - vb.net

This is the first challenge on Day 1 of the 2018 Advent of Code
(link: https://adventofcode.com/2018/day/1)
So I am trying to create a program that reads a long list of positive and negative numbers (e.g +1, -2, +3, etc.) and then add them up to create a total. I have researched some methods of file handling in Visual Basic, and have come up with the below method:
Sub Main()
Dim objStreamReader As StreamReader
Dim strLine As String = ""
Dim total As Double = 0
objStreamReader = New StreamReader(AppDomain.CurrentDomain.BaseDirectory & "frequencies.txt")
strLine = objStreamReader.ReadLine
Do While Not strLine Is Nothing
Console.WriteLine(strLine)
strLine = objStreamReader.ReadLine
total += strLine
Loop
Console.WriteLine(total)
objStreamReader.Close()
Console.ReadLine()
End Sub
Here is a link to the list of numbers: https://adventofcode.com/2018/day/1/input
It is not a syntax error I am getting but a logic error. The answer is somehow wrong, but I cannot seem to figure out where! I have tried to remove the signs from each number but that throws me a NullException error when it compiles.
So far I have come out with the answer 549, which the Advent of Code webiste rejects. Any ideas?

Make your life easier by using File.ReadLines(fileName) instead of dealing with StreamReader. Use Path.Combine instead of string concatenation to create a path. Path.Combine takes care of adding missing \ or removing extra ones etc.
Your file might contain an extra empty line at its end, that does not convert to a number. Use Double.TryParse to make sure you have a valid number before totalizing it. You should have Option Strict On anyway to enforce explicit conversions.
Dim fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "frequencies.txt")
Dim total As Double = 0
For Each strLine As String In File.ReadLines(fileName)
Console.WriteLine(strLine)
Dim n As Double
If Double.TryParse(strLine, n) Then
total += n
End If
Next
Console.WriteLine(total)
Console.ReadLine()

For appending two string, please use string builder.
Dim test as new stringbuilder()
Test.append("your string")
It will not affect performance.

Related

Count words in an external file using delimiter of a space

I want to calculate the number of words in a text file using a delimiter of a space (" "), however I am struggling.
Dim counter = 0
Dim delim = " "
Dim fields() As String
fields = Nothing
Dim line As String
line = Input
While (SR.EndOfStream)
line = SR.ReadLine()
End While
Console.WriteLine(vbLf & "Reading File.. ")
fields = line.Split(delim.ToCharArray())
For i = 0 To fields.Length
counter = counter + 1
Next
SR.Close()
Console.WriteLine(vbLf & "The word count is {0}", counter)
I do not know how to open the file and to get the do this, very confused; would like an explanation so I can edit and understand from it.
You're going to be reading a file as the source of the data, so let's create a variable to refer to its filename:
Dim srcFile = "C:\temp\twolines.txt"
As you have shown already, a variable is needed to hold the number of words found:
Dim counter = 0
To read from the file, a StreamReader will do the job. Now, we look at the documenation for it (yes, really) and notice that it has a Dispose method. That means that we have to explicitly dispose of it after we've used it to make sure that no system resources are tied up until the computer is next rebooted (e.g there could be a "memory leak"). Fortunately, there is the Using construct to take care of that for us:
Using sr As New StreamReader(srcFile)
And now we want to iterate over the content of the file line-by-line until the end of the file:
While Not sr.EndOfStream
Then we want to read a line and find how many items separated by spaces it has:
counter += sr.ReadLine().Split({" "c}, StringSplitOptions.RemoveEmptyEntries).Length
The += operator is like saying "add n to a" instead of saying "a = a + n". The {" "c} is a literal array of the character " "c. The c tells it that is a character and not a string of one character. The StringSplitOptions.RemoveEmptyEntries means that if there was text of "one two" then it would ignore the extra spaces.
So, if you were writing a console program, it might look like:
Imports System.IO
Module Module1
Sub Main()
Dim srcFile = "C:\temp\twolines.txt"
Dim counter = 0
Using sr As New StreamReader(srcFile)
While Not sr.EndOfStream
counter += sr.ReadLine().Split({" "c}, StringSplitOptions.RemoveEmptyEntries).Length
End While
End Using
Console.WriteLine(counter)
Console.ReadLine()
End Sub
End Module
Any embellishments such as writing out what the number represents or error checking are left up to you.
With Path.Combine you don't have to worry about where the slashes or back slashes go. You can get the path of special folders easily using the Environment class. The File class of System.IO is shared so you don't have to create an instance.
Public Sub Main()
Dim p As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Chapters.txt")
Debug.Print(Environment.SpecialFolder.MyDocuments.ToString)
Dim count As Integer = GetCount(p)
Console.WriteLine(count)
Console.ReadKey()
End Sub
Private Function GetCount(Path As String) As Integer
Dim s = File.ReadAllText(Path)
Return s.Split().Length
End Function
Use Split function, then Directly get the length of result array and add 1 to it.

VB.net How to remove quotes characters from a streamReader.readline.split()

I had built a project that read data from a report and it used to work fine but now for some reason the report puts every thing in to strings. So I want to modify my stream reader to remove or ignore the quotes as it reads the lines.
This is a snipet of the part that reads the lines.
Dim RawEntList As New List(Of Array)()
Dim newline() As String
Dim CurrentAccountName As String
Dim CurrentAccount As Account
Dim AccountNameExsists As Boolean
Dim NewAccount As Account
Dim NewEntry As Entrey
Dim WrongFileErrorTrigger As String
ListOfLoadedAccountNames.Clear()
'opens the file
Try
Dim sr As New IO.StreamReader(File1Loc)
Console.WriteLine("Loading full report please waite")
MsgBox("Loading full report may take a while.")
'While we have not finished reading the file
While (Not sr.EndOfStream)
'spliting eatch line up into an array
newline = sr.ReadLine.Split(","c)
'storring eatch array into a list
RawEntList.Add(newline)
End While
And then of course I iterate through the list to pull out information to populate objects like this:
For Each Entr In RawEntList
CurrentAccountName = Entr(36)
AccountNameExsists = False
For Each AccountName In ListOfLoadedAccountNames
If CurrentAccountName = AccountName Then
AccountNameExsists = True
End If
Next
You could just do
StringName.Replace(ControlChars.Quote, "")
or
StringName.Replace(Chr(34), "")
OR
streamReader.readline.split().Replace(Chr(34), "")
How about doing the replace before the split, after the readline? That should save iteration multiplication, or better yet (if possible), do a replace on the entire file (if the data is formatted in the way it can be done & you have enough memory) using the ReadAllText method of the File object, do your replace, then read the lines from memory to build your array (super fast!).
File.ReadAllText(path)

VB.net split function with substring

I want to read a certain value in a string. each line is a new string and I want to read the 6th integer on each line..
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles browsebtn.Click
If OpenFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim filename As String = OpenFileDialog1.FileName
Dim streamreader As New System.IO.StreamReader(filename)
Dim textfile As String = streamreader.ReadToEnd
Dim splitChar As String = vbNewLine
Dim day As Integer = textfile.Substring(10, 2)
Dim strLine() As String = day.Split(splitChar)
For Each line As String In strLine
MsgBox(day)
Next
End If
End Sub
End Class
But it only returns one number. If I set day as a string and not an integer it works perfect, except it reads the whole string, not the two integers that I need. Please help. What am I doing wrong?
EDIT:
The input file looks like this:
23728 121010 00004986 00 00 2 21 22 11 447 114 2 382 292 350
23730 121010 00064120 00 00 51 19 21 12 1064 110 2 4500 572 7734
I want my output to be:
10
10
10 comes from "121010"
All of that code that you wrote could be done in much fewer lines, like this:
For Each line As String In File.ReadAllLines(fileName)
MessageBox.Show(line)
Next
Like your example, though, that loads the entire file into memory all at once, which could be problematic if it's a large file. If the size of the file is a concern, it would be better to just read one line at a time, like this:
Dim streamReader As New StreamReader(fileName)
Dim line As String = Nothing
Do
line = streamReader.ReadLine()
MessageBox.Show(line)
Loop Until line Is Nothing
However, the problem still remains, how do you split the line up into its individual values. If, as it appears in your question, the values are separated by spaces, then you can just use line.Split to separate the line into an array of all of its values. Then to get the last two characters of one of those values, you can just use String.SubString, like this:
Dim streamReader As New StreamReader(fileName)
Dim line As String = Nothing
Do
line = streamReader.ReadLine()
Dim parts() As String = line.Split()
Dim wholeNumber As String = parts(1)
Dim lastTwo As String = wholeNumber.SubString(wholeNumber.Length - 2)
MessageBox.Show(lastTwo)
Loop Until line Is Nothing
Some advice:
always dispose resources (use using or try catch finally with
resource.close)
never trust user inputs.
write codes that can handle enough undesired situations
Corrections based on your code:
Try
Dim text As String = Nothing
Using streamreader As New System.IO.StreamReader("text.txt")
text = streamreader.ReadToEnd()
End Using
If IsNothing(text) = False Then
Dim strLine() As String = text.Split(New String() {Environment.NewLine}, StringSplitOptions.None)
For Each line As String In strLine
If line.Length > 12 Then MsgBox(line.Substring(10, 2))
Next
End If
Catch ex As Exception
'filenotfound case
End Try
Another way:
On cases where line input can be different (but second should be looked value in our case)
Then can use Regex
Here is how:
Try
Using streamreader As New System.IO.StreamReader(file)
Dim line As String
While streamreader.Peek > 0
'unreaded line from file
line = streamreader.ReadLine()
'split input by non digits
Dim numberstrs As String() = Regex.Split(line, "\D+")
'second numbers last two
If numberstrs.Length > 1 AndAlso numberstrs(1).Length > 2 Then
Console.WriteLine("{0}", numberstrs(1).Substring(numberstrs(1).Length - 2, 2))
End If
End While
End Using
Catch ex As Exception
End Try
Steven's answer gets you most of the way there but not all the way. It's worth noting that you actually don't want the 6th integer because that could be 1 or 2 or pretty much anything depending on how you slice it. Also, given in your example you say you want to get 10 from 121010, that could be wither the second group of two numbers or the third group of two numbers from that section of the string.
I note that in your example strings you have some double spaces: You need to sort that out for a kickoff otherwise using String.Split will give you empty elements in the array. In fact, using parts(5) as Steven has used above gives you an empty element thanks to the double space, and that's not what you want anyway. You would want parts(2) and then you would need to SubString that to get the number you want.
Another, and I think more elegant, way to do it is to use a RegEx to get the number. Let's say you want the second 10 in that string (shown in bold): 12*10*10. If you know that that string will always be 6 characters, will always be the second field in the input line and you always want the third and fourth numbers then this would do you:
Imports System.Text.RegularExpressions
Imports System.IO
Private Sub ReadFile
Dim rx As New Regex("^[^\s]+\s{1}\d{2}(\d{2}?)", RegexOptions.Compiled Or RegexOptions.CultureInvariant)
Dim streamReader As New StreamReader(fileName)
Dim line As String = String.Empty
Do While streamReader.Peek >= 0
line = streamReader.ReadLine()
MessageBox.Show(rx.Matches(line)(0).Groups(1).Value)
Loop
End Sub
I'm not saying that's the only (or most elegant) RegEx but it will work and means you don't have to use SubString and it doesn't care how long the first field is. It also assumes a single space between fields but that can also be changed to suit. So long as you can work out a rule to get to the bit you want, you can RegEx it. Use Expresso (free and very powerful utility) to help you construct a suitable expression.

Visual Basic Read File Line by Line storing each Line in str

I am trying to loop through the contents of a text file reading the text file line by line. During the looping process there is several times I need to use the files contents.
Dim xRead As System.IO.StreamReader
xRead = File.OpenText(TextBox3.Text)
Do Until xRead.EndOfStream
Dim linetext As String = xRead.ReadLine
Dim aryTextFile() As String = linetext.Split(" ")
Dim firstname As String = Val(aryTextFile(0))
TextBox1.Text = firstname.ToString
Dim lastname As String = Val(aryTextFile(0))
TextBox2.Text = lastname.ToString
Loop
Edit: What I am trying to do is read say the first five items in a text file perform some random processing then read the next 5 lines of the text file.
I would like to be able to use the lines pulled from the text file as separated string variables.
It is not clear why you would need to have 5 lines stored at any time, according to your code sample, since you are only processing one line at a time. If you think that doing 5 lines at once will be faster - this is unlikely, because .NET maintains caching internally, so both approaches will probably perform the same. However, reading one line at a time is a much more simple pattern to use, so better look into that first.
Still, here is an approximate version of the code that does processing every 5 lines:
Sub Main()
Dim bufferMaxSize As Integer = 5
Using xRead As New System.IO.StreamReader(TextBox3.Text)
Dim buffer As New List(Of String)
Do Until xRead.EndOfStream
If buffer.Count < bufferMaxSize Then
buffer.Add(xRead.ReadLine)
Continue Do
Else
PerformProcessing(buffer)
buffer.Clear()
End If
Loop
If buffer.Count > 0 Then
'if line count is not divisible by bufferMaxSize, 5 in this case
'there will be a remainder of 1-4 records,
'which also needs to be processed
PerformProcessing(buffer)
End If
End Using
End Sub
Here is mine . Rely easy . Just copy the location from the file and copy1 folder to does locations . This is my first program :) . ready proud of it
Imports System.IO
Module Module1
Sub Main()
For Each Line In File.ReadLines("C:\location.txt".ToArray)
My.Computer.FileSystem.CopyDirectory("C:\Copy1", Line, True)
Next
Console.WriteLine("Done")
Console.ReadLine()
End Sub
End Module

.split removes tabs/spaces in string?

i am trying to split a string up into separate lines with the following code, but for some reason it is also removing the spaces in the string.
Dim calculationText As String
calculationText = File.ReadAllText(fileName)
Dim fields() As String
fields = calculationText.Split(vbCrLf)
when i am in debugger mode, i look at fields, and every element has a line of the string but all the spaces and tabs are removed.
any reason for this?
If you are reading from a file, can you use:
Sub Main()
Dim fields As New List(Of String)
' read file into list
Using sr As System.IO.StreamReader = My.Computer.FileSystem.OpenTextFileReader(filename)
Try
Do While sr.Peek() >= 0
fields.Add(sr.ReadLine())
Loop
Finally
If sr IsNot Nothing Then sr.Close()
End Try
End Using
' check results
For Each line As String In fields
Console.WriteLine(line)
Next
End Sub
How 'bout:
Dim fields() As String = File.ReadAllLines(fileName)
As for why string.Split() is doing weird things...
vbCrLf is a string, and there's not an overload for string.split that accepts a single string parameter. If he were to turn on Option Explicit it wouldn't even compile, but since it's off, vbCrLf can be interpreted as an array of characters. And in this code, that's exactly what happens:
Sub Main()
Dim z As String = "The quick brown" & vbCrLf & " fox jumps over the lazy dogs."
Dim a() As String = z.Split(vbCrLf)
For Each c As String In a
Console.WriteLine(c)
Next
Console.ReadKey(True)
End Sub
You'll see two line breaks between the 1st and 2nd parts of that string. Something else is stripping out the spaces. Can you share the larger code block?
Gotta say I've never seen it do that, and I've used String.Split extensively. Are they really really gone, or is it a trick of the debugger?
There's not actually any .Split method that takes one string as the parameter, so the VB compiler would be doing "things" behind the scenes to pick a different overload. To try and force the correct overload, you could try calculationText.Split(vbCrLf.ToCharArray()). I doubt it will help, but you never know :-)