Extract field lengths - vb.net

I want to read fixed length files.
I know how to do this if I know the field lengths.
Using Reader As New Microsoft.VisualBasic.FileIO.TextFieldParser(filePath)
Reader.TextFieldType =
Microsoft.VisualBasic.FileIO.FieldType.FixedWidth
Reader.SetFieldWidths(8, 16, 16, 12, 14, 16) 'They are different in each file
Dim currentRow As String()
While Not Reader.EndOfData
Try
currentRow = Reader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
MsgBox(currentField)
Next
Catch ex As Microsoft.VisualBasic.
FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
"is not valid and will be skipped.")
End Try
End While
End Using
The problem is that I don't know the length of each field.
Is there a way to read the first line and get the Field lengths?

Since I have found the answer, I'll post it here in case someone will face the same problem.
I solved it using regex
'sRowData is the first line of the file
Dim pArLengths() As Integer = Nothing 'Array to store the lengths
Dim regex As New Regex("[^\W_\d]+", _
RegexOptions.IgnoreCase _
Or RegexOptions.Multiline _
Or RegexOptions.Singleline _
Or RegexOptions.IgnorePatternWhitespace)
Dim myMatches As MatchCollection = regex.Matches(sRowData)
ReDim pArLengths(myMatches.Count - 1)
For i = 0 To myMatches.Count - 1
Dim k As Integer
k = If(i < myMatches.Count - 1, myMatches(i + 1).Index, sRowData.Length)
pArLengths(i) = k - myMatches(i).Index
Next
I hope that someone will find it useful.

Related

“Input string was not in a correct format” while parsing the content of a file

I need help, I don't know why the array for the quantity in my input file strArr(1) having an error that says that the input string was not in a correct format.
Dim objReader As IO.StreamReader
Dim objWriter As New IO.StreamWriter("C:\Users\user\Desktop\StationeryFolder\output.txt")
Dim strLine As String
Dim strName As String
Dim intQuantity As Integer
Dim intTotal As Integer
Dim strArr() As String
If IO.File.Exists("C:\Users\user\Desktop\StationeryFolder\input.txt") = True Then
objReader = IO.File.OpenText("C:\Users\user\Desktop\StationeryFolder\input.txt")
Else
MsgBox("File is not exist")
Close()
End If
Do While objReader.Peek <> -1
strLine = objReader.ReadLine()
strArr = strLine.Split(" ")
strName = strArr(0)
intQuantity = Convert.ToInt32(strArr(1)) //this is where the error occurs
intTotal = intTotal + intQuantity
lstDisplay.Items.Add(strName & " " & intQuantity.ToString())
objWriter.WriteLine(strName & " " & intQuantity.ToString())
Loop
lstDisplay.Items.Add("Total Quantity of Stationeries are: " & intTotal.ToString())
objWriter.WriteLine("Total Quantity of Stationeries are: " & intTotal.ToString())
objReader.Close()
objWriter.Close()
Inside the input file:
Markers
15
Pens
25
I used the .net File class instead of streams. ReadAllLine returns an array of the lines in the file. I used a StringBuilder which is mutable (changeable) unlike a String. Saves the code from creating and throwing away several strings. I have used interpolated strings indicated by the $ before the quotes. This allows inserting variables directly into the string surrounded by braces.
Private Sub OPCode()
Dim inputPath = "C:\Users\user\Desktop\StationeryFolder\input.txt"
If Not IO.File.Exists(inputPath) Then
MsgBox("File does not exist")
Close()
End If
Dim lines = File.ReadAllLines(inputPath)
Dim total As Integer
Dim sb As New StringBuilder
For i = 0 To lines.Length - 2 Step 2
lstDisplay.Items.Add($"{lines(i)} {lines(i + 1)}")
sb.AppendLine($"{lines(i)} {lines(i + 1)}")
total += CInt(lines(i + 1))
Next
lstDisplay.Items.Add($"Total Quantity of Stationeries are: {total}")
sb.AppendLine($"Total Quantity of Stationeries are: {total}")
File.WriteAllText("C:\Users\user\Desktop\StationeryFolder\output.txt", sb.ToString)
End Sub

How to eliminate some rows and columns from a CSV file and save to new CSV?

I have a csv file, where the first 3 rows have unwanted data. The 4th row has needed data in the first column only. There are 4 more rows with unwanted data. Rows 9 through the end have needed data. Starting with row 9 there are 11 columns of data, columns 1 through 6 are needed, columns 7 through 11 are unwanted.
I have code that uses a DataGridView for temporary storage. It provides the parsing described above, however I don't need to view the data, I need to create a new CSV file resulting from the parsing.
There is probably a method using a data table for temporary storage, instead of the DataGridView, however maybe there is a simpler way using LINQ. I have no experience with LINQ and my experience with data tables is very limited. I am very comfortable with DataGridView since I use it extensively, but as I wrote earlier I don't need to display the result.
I tried the code in: https://www.codeproject.com/questions/634373/how-to-delete-the-rows-in-csv-file. But it doesn't fit my situation. The code below works using a DataGridView for temporary storage but I am sure there is a better way.
Using MyReader As New TextFieldParser(racerFile)
Dim currentRow As String()
MyReader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {","}
currentRow = MyReader.ReadFields()
currentRow = MyReader.ReadFields()
currentRow = MyReader.ReadFields()
boatClass = MyReader.ReadFields()(0)
currentRow = MyReader.ReadFields()
currentRow = MyReader.ReadFields()
currentRow = MyReader.ReadFields()
currentRow = MyReader.ReadFields()
While Not MyReader.EndOfData
Try
Dgvs.Rows.Add()
currentRow = MyReader.ReadFields()
Dgvs(0, rd).Value = boatClass
Dgvs(1, rd).Value = currentRow(1)
Dgvs(2, rd).Value = currentRow(2)
Dgvs(3, rd).Value = currentRow(3)
Dgvs(4, rd).Value = currentRow(4)
Dgvs(5, rd).Value = currentRow(5)
rd += 1
Catch ex As Exception
End Try
End While
End Using
Using WriteFile As New StreamWriter(myFile)
For x As Integer = 0 To Dgvs.Rows.Count - 1
For y As Integer = 0 To Dgvs.Columns.Count - 1
WriteFile.Write(Dgvs.Rows(x).Cells(y).Value)
If y <> Dgvs.Columns.Count - 1 Then
WriteFile.Write(", ")
End If
Next
WriteFile.WriteLine()
Next
End Using
I need a CSV file for output.
Instead of storing values in a DatGridView, you could store them in a List(Of String), where each string in the list is a line of the output csv file.
Dim output As New List(Of String)
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
Dim line As String
line = boatClass
line = line & "," & currentRow(1).ToString
line = line & "," & currentRow(2).ToString
line = line & "," & currentRow(3).ToString
line = line & "," & currentRow(4).ToString
line = line & "," & currentRow(5).ToString
output.Add(line)
Catch ex As Exception
End Try
End While
And then you write output lines as follows.
Using WriteFile As New StreamWriter(myFile)
For Each line As String In output
WriteFile.Write(line)
Next
End Using

Split in VB.net

FASTER,WW0011,"CTR ,REURN,ALT TUBING HELIUM LEAK",DEFAULT test,1,3.81,test
I need to get the result of the following line as
Arr(0) =faster
Arr(1) =WW0011
Arr(2) =CTR ,REURN,ALT TUBING HELIUM LEAK
Arr(3) =DEFAULT test
Arr(4) =faster
Arr(5) = 1
Arr(6)=3.81
Arr(7) = test
I tried using split, but the problem is on Arr(2)
could anyone please give me a solution
You could use the TextFieldParser class which will take care of situations like this. Set the HasFieldEnclosedInQuotes property to true. Here is an example from MSDN (slightly altered):
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser("c:\logs\bigfile")
MyReader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {","}
'Set this to ignore commas in quoted fields.
MyReader.HasFieldsEnclosedInQuotes = True
Dim currentRow As String()
'Loop through all of the fields in the file.
'If any lines are corrupt, report an error and continue parsing.
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
' Include code here to handle the row.
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & " is invalid. Skipping")
End Try
End While
End Using
I use this function alot myself
Private Function splitQuoted(ByVal line As String, ByVal delimeter As Char) As String()
Dim list As New List(Of String)
Do While line.IndexOf(delimeter) <> -1
If line.StartsWith("""") Then
line = line.Substring(1)
Dim idx As Integer = line.IndexOf("""")
While line.IndexOf("""", idx) = line.IndexOf("""""", idx)
idx = line.IndexOf("""""", idx) + 2
End While
idx = line.IndexOf("""", idx)
list.Add(line.Substring(0, idx))
line = line.Substring(idx + 2)
Else
list.Add(line.Substring(0, Math.Max(line.IndexOf(delimeter), 0)))
line = line.Substring(line.IndexOf(delimeter) + 1)
End If
Loop
list.Add(line)
Return list.ToArray
End Function
Use a for loop to iterate the string char by char!

extracting text from comma separated values in visual basic

I have such kind of data in a text file:
12343,M,Helen Beyer,92149999,21,F,10,F,F,T,T,T,F,F
54326,F,Donna Noble,92148888,19,M,99,T,F,T,F,T,F,T
99999,M,Ed Harrison,92147777,28,F,5,F,F,F,F,F,F,T
88886,F,Amy Pond,92146666,31,M,2,T,F,T,T,T,T,T
37378,F,Martha Jones,92144444,30,M,5,T,F,F,F,T,T,T
22444,M,Tom Scully,92145555,42,F,6,T,T,T,T,T,T,T
81184,F,Sarah Jane Smith,92143333,22,F,5,F,F,F,T,T,T,F
97539,M,Angus Harley,92142222,22,M,9,F,T,F,T,T,T,T
24686,F,Rose Tyler,92142222,22,M,5,F,F,F,T,T,T,F
11113,F,Jo Grant,92142222,22,M,5,F,F,F,T,T,T,F
I want to extract the Initial of the first name and complete surname. So the output should look like:
H. Beyer, M
D. Noble, F
E. Harrison, M
The problem is that I should not use String Split function. Instead I have to do it using any other way of string handling.
This is my code:
Public Sub btn_IniSurGen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_IniSurGen.Click
Dim vFileName As String = "C:\temp\members.txt"
Dim vText As String = String.Empty
If Not File.Exists(vFileName) Then
lbl_Output.Text = "The file " & vFileName & " does not exist"
Else
Dim rvSR As New IO.StreamReader(vFileName)
Do While rvSR.Peek <> -1
vText = rvSR.ReadLine() & vbNewLine
lbl_Output.Text += vText.Substring(8, 1)
Loop
rvSR.Close()
End If
End Sub
You can use the TextFieldParserClass. It will parse the file and return the results directly to you as a string array.
Using MyReader As New Microsoft.VisualBasic.FileIO.
TextFieldParser("c:\logs\bigfile")
MyReader.TextFieldType =
Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {","}
Dim currentRow As String()
'Loop through all of the fields in the file.
'If any lines are corrupt, report an error and continue parsing.
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
' Include code here to handle the row.
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
" is invalid. Skipping")
End Try
End While
End Using
For your wanted result, you may changed
lbl_Output.Text += vText.Substring(8, 1)
to
'declare this first
Dim sInit as String
Dim sName as String
sInit = vText.Substring(6, 1)
sName = ""
For x as Integer = 8 to vText.Length - 1
if vText.Substring(x) = "," Then Exit For
sName &= vText.Substring(x)
Next
lbl_Output.Text += sName & ", " & sInit
But better you have more than one lbl_Output ...
Something like this should work:
Dim lines As New List(Of String)
For Each s As String In File.ReadAllLines("textfile3.txt")
Dim temp As String = ""
s = s.Substring(s.IndexOf(","c) + 1)
temp = ", " + s.First
s = s.Substring(s.IndexOf(","c) + 1)
temp = s.First + ". " + s.Substring(s.IndexOf(" "c), s.IndexOf(","c) - s.IndexOf(" "c)) + temp
lines.Add(temp)
Next
The list Lines will contain the strings you need.

How to read a delimited line of strings and ints and extract them for processing in VB

I have the following text file (ExamMarks.txt)
John, 85, 95, 90
Micheal, 60, 75, 75
I want to extract a line and take the Name and separately and the ints separately. Then I want to print the name and the average of the numbers like this in a label:
John's average is 90
Micheal's average is 70
So far I can only display what is in the text file in a label (see below):
Dim FILE_NAME As String = "C:\ExamMarks.txt"
Dim TextLine As String
If System.IO.File.Exists(FILE_NAME) = True Then
Dim objReader As New System.IO.StreamReader(FILE_NAME)
Do While objReader.Peek() <> -1
TextLine = TextLine & objReader.ReadLine & vbNewLine
Loop
lblResults.Text = TextLine
Else
MsgBox("File Does Not Exist")
End If
Any help is appreciated.
Do this processing for each of the lines in the file. It assumes that the name is always the first word in the string, then it calculates the average of all the numbers in the string.
'Split the test string on commas
Dim strScores() As String = strTest.Split(",".ToCharArray)
Dim strWord As String
Dim intTotalScore As Integer
Dim intCountOfScores As Integer
Dim intAverageScore As Integer
'Name is the first word in the line
strName = strScores(1).Trim
For Each strWord In strScores
If IsNumeric(strWord) Then
intTotalScore = intTotalScore + Int(strWord.Trim)
intCountOfScores = intCountOfScores + 1
End If
Next
'Calculate the average
intAverageScore = intTotalScore / intCountOfScores
You can do all this much more briefly with some more modern code:
Use the built-in TextFieldParser to read the comma-separated file, and access each row as a string array. It's simpler and more robust than using Split.
And then use IEnumerable extension methods to calculate the average all in one line.
a. Skip(1) skips the first entry.
b. Average() lets you convert the remaining entries to Double and then take the average.
Like this:
Sub Main()
Using MyReader As New _
Microsoft.VisualBasic.FileIO.TextFieldParser("ExamMarks.txt")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
While Not MyReader.EndOfData
Try
' Read row as an array of strings '
currentRow = MyReader.ReadFields()
' Calculate average '
Dim dAverage As Double = _
currentRow.Skip(1).Average(Function(s) Convert.ToDouble(s))
' Write out result '
Console.WriteLine(currentRow(0) & "'s average is " & _
Convert.ToString(dAverage))
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & "is not valid and will be skipped.")
End Try
End While
End Using
Console.ReadLine()
End Sub