Using VB.NET (VS2013) I'd like to read a delimited file and remove a field if all records have the same blank field (could be multiple fields per record). The delimited file can have "x" number of columns and "y" number of rows and once the blank fields are removed, I need to write it back out as a new delimited file.
The input file will have a header that has to be maintained and the order of the records has to be maintained. I'm familiar with using TextParser to read the file and familiar with writing the file -- what I need help with is reading for a blank field and removing it if it exists across the entire file.
I was thinking I would have to use a datagrid but never used them so looking for some insight to point me in the direction.
Thanks!
I assume each line is delimited with a newline... open as a text file, read a line at a time and use the Split method to break up the line into an array of strings. The split method will take an argument that defines the delimiter you are using. Open the destination file and write the array of strings using a loop.
UPDATE
After thinking about it, you may have records that have a couple of blank columns and the rest have data. I'm not sure if you'd want to remove those columns, because you would lose the structure of the row if you did.
So instead of using StringSplitOptions.RemoveEmptyEntries, you can just do the Split() and then perform some Linq to find out if the Split() produced an array of empty strings.
Something like (with the same results)...
Imports System
Imports System.Linq
Public Module Module1
Public Sub Main()
Dim data As String = "|||||"
Dim pieces As String() = data.Split("|"c)
If pieces.Where(Function(p) String.IsNullOrEmpty(p) = False).Count = 0 Then
Console.WriteLine("All elements are empty")
Else
' Do something
End If
End Sub
End Module
Demo
OLD ANSWER
The String.Split() has an overload that excepts StringSplitOptions. Use StringSplitOptions.RemoveEmptyEntries with your String.Split() and if all records are blank then you'll end up with an array with a length of 0 that you can ignore.
Imports System
Public Module Module1
Public Sub Main()
Dim data As String = "|||||"
Dim pieces As String() = data.Split(new Char() {"|"}, StringSplitOptions.RemoveEmptyEntries)
If pieces.length = 0 Then
Console.WriteLine("All elements are empty")
Else
' Do something
End If
End Sub
End Module
Results:
All elements are empty
Demo
Related
I'm trying to make a small VB program to remove duplicate lines and empty lines from plain text.
I have the RichTextBox input but eventually I do not know what the type of the returned object is, is it an array or a list maybe ?
Also I'm trying to find the most efficient way to remove duplicate lines from big plain text(s), in Python I do it this way :
lines_nodupes = {}
for elt in lines :
lines_nodupes[elt] = ""
Since you can not have twice the same key, no duplicates are kept in the lines_nodupes dictionnary and I can enumerate it to access the lines.
There are two properties you can use :
Lines will return an array of Strings
Text will return the entire text as a string
See RichTextBox from MSDN
If you want to do as in Python :
Dim noDup as new Dictionary(Of String, String)
For Each line in MyRichTextBox.Lines
if not noDup.ContainsKey(line) then
noDUp.add(line, "")
End if
Next
You can also do (as suggested by VisualVincent in the coments) :
Dim noDup as new List(Of String)
For Each line in MyRichTextBox.Lines
if not noDup.Contains(line) then
noDUp.add(line)
End if
Next
which is a bit slower but difference won't be seen unless you have a very long list of items.
I am reading data in from a text file. I know that each piece of data is separated by a comma and it looks like this in the text file:
"Requisition","Supplies Req GL.pdf","05/28/2014","8,200.00","0510","86107RC"
Here's where I am drawing a blank. The 4th piece of data on the line can contain commas, so when I do a split on the data, it also splits that piece as well.
How can I read this in, separate the data and also keep column 4 in tact.
If you know it's that field, then just join them together... a little hokey but it works:
Dim inLine As String()
Dim columns As New List(Of String)
Using sr as As New IO.StreamReader(args(0))
While Not sr.EndOfStream
inLine = sr.ReadLine.Trim().Split(CChar(","))
columns.Add(inLine(0))
columns.Add(inLine(1))
columns.Add(inLine(2))
If inLine.Length > 6 Then
columns.Add(inLine(3) & inLine(4))
columns.Add(inLine(5))
columns.Add(inLine(6))
Else
columns.Add(inLine(3))
columns.Add(inLine(4))
columns.Add(inLine(5))
End If
End While
End Using
I'm trying like crazy to figure out how to do this. I need to look at a textfile that I've designed (for a quiz program)- line by line (the line having two parts separated by a comma) for the question (First part) and the boolean answer (second part). Ie. A line from the text file will look like:
You have 10 fingers,true
you have 10 toes,true
you have 2 thumbs,true
I just need to be able to convert this to an array whereby I can access the elements on command, so for instance (0,0) would display the first question in a textbox, and I would reference the users answer (in the form of true or false) against (0,1) where I would use a counter to count the number of correct answers. After the user answers the first question I could loop to the second question to be displayed in the array and so forth. Although there may be more advanced ways of doing this I will need to use a stream reader in this context.
I see I can read ONE line into an array with :
dim line() as string = io.file.readalllines("C:\data.txt")
dim value(2) as integer
value = line.split(","c)
but I need to access each line, with their answers, one at a time. If I could get the textfile into an two dimensional array I could simply access each element on command. Help :)
Any help would be GREATLY appreciated!
I suggest to use a proper class to handle your data. For example you could write a class named QA that stores the Question text and the boolean value of the answer
Public Class QA
Public Question as String
Public Answer as Boolean
End Class
You could read your file with File.ReadLines or use the StreamReader class.
Sub Main
' A list of QA objects loaded from file
Dim qaList as New List(Of QA)()
Using sw = new StreamReader("C:\data.txt")
Dim line as String
Do
line = sw.ReadLine()
If line Is Nothing Then Exit Do
Dim parts() = line.Split(","c)
' Initialize a new QA object and add it to the list
qaList.Add(new QA() _
With
{
.Question = parts(0),
.Answer = Convert.ToBoolean(parts(1))
})
Loop
End Using
Now you could use the List(Of QA) as an array referencing the elements using an indexer
Console.WriteLine(qaList(0).Question)
Console.WriteLine(qaList(0).Answer)
End Sub
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
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 :-)