CSV Data handling - vb.net - vb.net

I've been asked at work to create a project to open a CSV and then use a set of conditions to change and save the data using Visual Basic.net (2010)
Although I am comfortable creating files in vb and opening them again into vb, I don't know how to declare the fields so I can query them. For example:
if field1 = "Yes" and field2 = "Blue" then textbox1.text = "abcd"
Then at a later stage I want to export a file which I'm happy doing where it writes lines to create a new CSV which could be Field1, textbox1.text, Field3 and so on
Also, would I have to declare line1.field1 and line2.field1 or could I declare line2.field1 as field25 for example or whatever the next sequential number may be?
Thanks

How are you going to read from the file?
If you do File.ReadAllLines
what does it return? A string array.
Does a string array have properties like line1? No, but they do have indexers.
How do you access an element in a string array? With a indexer,
e.g. array(0).
Does an string have properties like field1? Nope.
Can you use String.Split to split on the commas and separate the fields? Yes.
Could you write a class that has specific properties defined for each field that has a constructor that'd take a string that represents a row and put the value into the correct fields? Yes.
Could the same class know how to convert itself into a single CSV style line? Yup.
Are there other library that could help you do this? Probably.
All that being said, you can probably get away with doing something simple like this (warning: naive code sample):
Dim fileName = "C:\testFile.csv"
Dim lines = File.ReadAllLines(fileName)
Dim output As New List(Of String)
For Each line In lines
Dim fields = line.Split(","c)
fields(0) = "000" 'Blank out number
If fields(3) = "Y" Then 'Change Y to True
fields(3) = "True"
End If
output.Add(String.Join(","c, fields))
Next
File.WriteAllLines(fileName, output)
I gave it input that looked like this:
123,abc,Y,Y,N
456,def,Y,N,Y
789,ghi,N,Y,Y
012,jkl,N,N,N
and it changed the file to this:
000,abc,Y,True,N
000,def,Y,N,Y
000,ghi,N,True,Y
000,jkl,N,N,N
Utilities for working with CSV will do a better job than this. There are various ways this won't work (doesn't handle any escape sequences, etc.) but this could be sufficient if you're just wanting to do something quick and dirty and don't need to worry about some things. At the very least hopefully it'll give you a better understanding of how you'd go about solving a problem like this.
I'd recommend writing the output to a different file to test.

Related

Match Words and Add Quantities vb.net

I am trying to program a way to read a text file and match all the values and their quantites. For example if the text file is like this:
Bread-10 Flour-2 Orange-2 Bread-3
I want to create a list with the total quantity of all the common words. I began my code, but I am having trouble understanding to to sum the values. I'm not asking for anyone to write the code for me but I am having trouble finding resources. I have the following code:
Dim query = From data In IO.File.ReadAllLines("C:\User\Desktop\doc.txt")
Let name As String = data.Split("-")(0)
Let quantity As Integer = CInt(data.Split("-")(1))
Let sum As Integer = 0
For i As Integer = 0 To query.Count - 1
For j As Integer = i To
Next
Thanks
Ok, lets break this down. And I not seen the LET command used for a long time (back in the GWBASIC days!).
But, that's ok.
So, first up, we going to assume your text file is like this:
Bread-10
Flour-2
Orange-2
Bread-3
As opposed to this:
Bread-10 Flour-2 Orange-2 Bread-3
Now, we could read one line, and then process the information. Or we can read all lines of text, and THEN process the data. If the file is not huge (say a few 100 lines), then performance is not much of a issue, so lets just read in the whole file in one shot (and your code also had this idea).
Your start code is good. So, lets keep it (well ok, very close).
A few things:
We don't need the LET for assignment. While older BASIC languages had this, and vb.net still supports this? We don't need it. (but you will see examples of that still floating around in vb.net - especially for what we call "class" module code, or "custom classes". But again lets just leave that for another day.
Now the next part? We could start building up a array, look for the existing value, and then add it. However, this would require a few extra arrays, and a few extra loops.
However, in .net land, we have a cool thing called a dictionary.
And that's just a fancy term of for a collection VERY much like an array, but it has some extra "fancy" features. The fancy feature is that it allows one to put into the handly list things by a "key" name, and then pull that "value" out by the key.
This saves us a good number of extra looping type of code.
And it also means we don't need a array for the results.
This key system is ALSO very fast (behind the scene it uses some cool concepts - hash coding).
So, our code to do this would look like this:
Note I could have saved a few lines here or there - but that would make this code hard to read.
Given that you look to have Fortran, or older BASIC language experience, then lets try to keep the code style somewhat similar. it is stunning that vb.net seems to consume even 40 year old GWBASIC type of syntax here.
Do note that arrays() in vb.net do have some fancy "find" options, but the dictionary structure is even nicer. It also means we can often traverse the results with out say needing a for i = 1 to end of array, and having to pull out values that way.
We can use for each.
So this would work:
Dim MyData() As String ' an array() of strings - one line per array
MyData = File.ReadAllLines("c:\test5\doc.txt") ' read each line to array()
Dim colSums As New Dictionary(Of String, Integer) ' to hold our values and sum them
Dim sKey As String
Dim sValue As Integer
For Each strLine As String In MyData
sKey = Split(strLine, "-")(0)
sValue = Split(strLine, "-")(1)
If colSums.ContainsKey(sKey) Then
colSums(sKey) = colSums(sKey) + sValue
Else
colSums.Add(sKey, sValue)
End If
Next
' display results
Dim KeyPair As KeyValuePair(Of String, Integer)
For Each KeyPair In colSums
Debug.Print(KeyPair.Key & " = " & KeyPair.Value)
Next
The above results in this output in the debug window:
Bread = 13
Flour = 2
Orange = 2
I was tempted here to write this code using just pure array() in vb.net, as that would give you a good idea of the "older" types of coding and syntax we could use here, and a approach that harks all the way back to those older PC basic systems.
While the dictionary feature is more advanced, it is worth the learning curve here, and it makes this problem a lot easier. I mean, if this was for a longer list? Then I would start to consider introduction of some kind of data base system.
However, without some data system, then the dictionary feature is a welcome approach due to that "key" value lookup ability, and not having to loop. It also a very high speed system, so the result is not much looping code, and better yet we write less code.

Grabbing sections of a text file - vb

Probably kick-self simple, but this is defeating me.
I have a text file which I am looking to grab in sections and populates separate text boxes. This is what the list looks like:
data_file_name
<1st section>
data
data
data
<2nd section>
data
data
data
etc.
Is there a way for me to take each section? I thought of changing the delimiter in a TextReader but some of the data also has the <> signs in it.
One way is to use system.io.file.readalllines(path) to read the file into a string array. Then process the array in memory sequentially, or using indexof, for "<1st section>", etc. This one approach of about a dozen that will work equally well.
Below is code to read each line of the file into a string. Then, you compare the string value to see if it looks like a new section. If so, do your new section code, else to your current section code
Dim reader as new streamreader(file.txt)
Dim inline as String
While reader.peek <> -1
inline = reader.readline
if inline.startswith("<") and inline.endswith(">") and inline.contains("section")
'do new section routine
else
'do current section routine
end if
end while
reader.close

How to compare strings inside a text file

I'm learning to read text files and Streamreader is the only class I know until now for that purpose.
Until now I've seen this class lets me read the entire file(.ReadToEnd), line by line(.ReadLine) or character by character(.Read).
However I can't figure how to read substrings delimited by , and solve this:
( Following 4 lines are the content of textfile.txt)
COLUMN1,MAIL1,COLUMN3,COLUMN4,COLUMN5,MAIL2
".","user#DOMAIN.EDU.PE","1","2013-05-08 00:00:00","0","user#DOMAIN.EDU.PE"
".","id#DOMAIN1.COM.PE","1","2013-05-08 00:00:00","0","HADSA7#DOMAIN1.COM.PE"
".","myid#DOMAIN2.COM.PE","1","2013-05-08 00:00:00","0","4671#DOMAIN2.COM.PE"
If the first email address is equal to the second, do:
Numberofmatched=Numberofmatched+1
If not
Numberofunmatched=Numberofunmatched+1
Take in consideration domain name can change and email addresses have variable lenght.
Any help?
Here's another method to read a text-file. You can use the System.IO.File class, for example File.ReadLines/File.ReadAllLines or File.ReadAllText.
Use String.Split to get a String(), one string for each column. Since the delimiter seems to be ,instead of " use String.Split(","c).
You can use following LINQ query which can increase readability:
Dim allLines = File.ReadAllLines("Path")
Dim data = From line In allLines.Skip(1) ' skip the header-line
Where Not String.IsNullOrWhiteSpace(line)
Let fields = line.Split(","c)
Where fields.Length = 6
Select fields
Dim Numberofmatched As Int32 = data.Count(Function(fields) fields(1) = fields(5))
Dim Numberofunmatched As Int32 = data.Count(Function(fields) fields(1) <> fields(5))
Note that you should use an available CSV-parser instead of reinventing the wheel since they support quoting characters and a lot of other things. One recommendable in the Visual-Basic namespace is the TextFieldParser class.

Parse String to Array or DataTable

I'm trying to parse a long boring text document and parse and format it.
"7/29/2012 1:25:20 PM","Summary Plan/Second Floor /Master_VAV_2-24","Source :OEnd"
"7/29/2012 11:25:23 AM","Summary Plan/Second Floor /Master_VAV_2-24","Source :OStart"
I'd like to parse each value between the quotes but I cant find anything online to help me, I believe it's a matter of knowing what to call it and search for.
"date", "location", "type" would be the 3 values I want to parse it into, then I could run a loop for each item in datatable and format it as required.
ANY HELP would be great, thank you!
I'm thinking of using RegEx to get the rows and add them manually to an array, something like this.
Dim rx As New Regex(",", RegexOptions.IgnoreCase Or RegexOptions.Multiline)
Dim matches As MatchCollection = rx.Matches(strSource)
For Each match As Match In matches
Dim matchValue As String = match.Value
If Not list.Contains(matchValue) Then
list.Add(matchValue)
End If
Next
This format appears to be CSV - use one of the many free and open source CSV parsers (google ".NET CSV parser" will return many results.
There is one that comes built in, in the Microsoft.VisualBasic.FileIO namespece - the TextFieldParser.

How can I read individual lines of a CSV file into a string array, to then be selectively displayed via combobox input?

I need your help, guys! :|
I've got myself a CSV file with the following contents:
1,The Compact,1.8GHz,1024MB,160GB,440
2,The Medium,2.4GHz,1024MB,180GB,500
3,The Workhorse,2.4GHz,2048MB,220GB,650
It's a list of computer systems, basically, that the user can purchase.
I need to read this file, line-by-line, into an array. Let's call this array csvline().
The first line of the text file would stored in csvline(0). Line two would be stored in csvline(1). And so on. (I've started with zero because that's where VB starts its arrays). A drop-down list would then enable the user to select 1, 2 or 3 (or however many lines/systems are stored in the file). Upon selecting a number - say, 1 - csvline(0) would be displayed inside a textbox (textbox1, let's say). If 2 was selected, csvline(1) would be displayed, and so on.
It's not the formatting I need help with, though; that's the easy part. I just need someone to help teach me how to read a CSV file line-by-line, putting each line into a string array - csvlines(count) - then increment count by one so that the next line is read into another slot.
So far, I've been able to paste the numbers of each system into an combobox:
Using csvfileparser As New Microsoft.VisualBasic.FileIO.TextFieldParser _
("F:\folder\programname\programname\bin\Debug\systems.csv")
Dim csvalue As String()
csvfileparser.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
csvfileparser.Delimiters = New String() {","}
While Not csvfileparser.EndOfData
csvalue = csvfileparser.ReadFields()
combobox1.Items.Add(String.Format("{1}{0}", _
Environment.NewLine, _
csvalue(0)))
End While
End Using
But this only selects individual values. I need to figure out how selecting one of these numbers in the combobox can trigger textbox1 to be appended with just that line (I can handle the formatting, using the string.format stuff). If I try to do this using csvalue = csvtranslator.ReadLine , I get the following error message:
"Error 1 Value of type 'String' cannot be converted to '1-dimensional array of String'."
If I then put it as an array, ie: csvalue() = csvtranslator.ReadLine , I then get a different error message:
"Error 1 Number of indices is less than the number of dimensions of the indexed array."
What's the knack, guys? I've spent hours trying to figure this out.
Please go easy on me - and keep any responses ultra-simple for my newbie brain - I'm very new to all this programming malarkey and just starting out! :)
Structure systemstructure
Dim number As Byte
Dim name As String
Dim procspeed As String
Dim ram As String
Dim harddrive As String
Dim price As Integer
End Structure
Private Sub csvmanagement()
Dim systemspecs As New systemstructure
Using csvparser As New FileIO.TextFieldParser _
("F:\folder\programname\programname\bin\Debug\systems.csv")
Dim csvalue As String()
csvparser.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
csvparser.Delimiters = New String() {","}
csvalue = csvparser.ReadFields()
systemspecs.number = csvalue(0)
systemspecs.name = csvalue(1)
systemspecs.procspeed = csvalue(2)
systemspecs.ram = csvalue(3)
systemspecs.harddrive = csvalue(4)
systemspecs.optical = csvalue(5)
systemspecs.graphics = csvalue(6)
systemspecs.audio = csvalue(7)
systemspecs.monitor = csvalue(8)
systemspecs.software = csvalue(9)
systemspecs.price = csvalue(10)
While Not csvparser.EndOfData
csvalue = csvparser.ReadFields()
systemlist.Items.Add(systemspecs)
End While
End Using
End Sub
Edit:
Thanks for your help guys, I've managed to solve the problem now.
It was merely a matter calling loops at the right point in time.
I would recommend using FileHelpers to do the reading.
The binding shouldn't be an issue after that.
Here is the Quickstart for Delimited Records:
Dim engine As New FileHelperEngine(GetType( Customer))
// To Read Use:
Dim res As Customer() = DirectCast(engine.ReadFile("FileIn.txt"), Customer())
// To Write Use:
engine.WriteFile("FileOut.txt", res)
When you get the file read, put it into a normal class and just bind to the class or use the list of items you have to do custom stuff with the combobox. Basically, get it out of the file and into a real class asap, then things will be easier.
At least take a look at the library. After using it, we use a lot more simple flat files since it is so easy, and we haven't written a file access routine since (for that kinda stuff).
http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.textfieldparser.aspx
I think your main problem is understanding how arrays work (hence the error message).
You can use split and join functions to convert strings into and out of arrays
dim s() as string = split("1,2,3",",") gives and array of strings with 3 elements
dim ss as string = join(s,",") gives you the string back
Firstly, it's actually really good that you are using the TextFieldParser for reading CSV files - most don't but you won't have to worry about extra commas and quoted text etc...
The Readline method only gives you the raw string, hence the "Error 1 Value of type 'String' cannot be converted to '1-dimensional array of String'."
What you may find easier with combo boxes etc is to use an object (e.g. 'systemspecs') rather than strings. Assign the CSV data to the objects and override the "ToString" method of the 'systemspecs' class to display in the combo box how you want with formatting etc. That way when you handle the SelectedIndexChanged event (or similar) you get the "SelectedItem" from the combo box (which can be Nothing so check) and cast it as the 'systemspecs' to use it. The advantage is that you are not restricted to display the exact data in the combo etc.
' in "systemspecs"...
Public Overrides Function ToString() As String
Return Name ' or whatever...
End Function ' ToString
e.g.
dim item as new systemspecs
item.ID = csvalue(1)
item.Name = csvalue(2)
' etc...
combobox1.Items.Add(item)
Let me know if that makes sense!
PK :-)