VB.Net Search for text and replace with file content - vb.net

This is a follow on question to a post I made. Append one file into another file
I need to search the master document for entities "&CH1.sgm" to "&CH33.sgm",
mark where they are in the master document and replace the entity call with the matching file "Chapter1.sgm" found in "fnFiles". I can change the file names and entities to anything if that will help.
My code copies the text of a file and appends it to the bottom of the master_document.sgm. But now I need it to be more intelligent. Search the Master document for entity markers, then replace that entity marker with that file contents match. The file number and entity number match up. e.g.(&CH1; and Bld1_Ch1.sgm)
Private Sub btnImport_Click(sender As Object, e As EventArgs) Handles btnImport.Click
Dim searchDir As String = txtSGMFile.Text 'Input field from form
Dim masterFile = "Bld1_Master_Document.sgm"
Dim existingFileMaster = Path.Combine(searchDir, masterFile)
'Read all lines of the Master Document
Dim strMasterDoc = File.ReadAllText(existingFileMaster) '// add each line as String Array.
'?search strMasterDoc for entities &Ch1.sgm
'?replace entity name "&Ch1.sgm" with content of file "Bld1_Ch1.sgm" this content if found below
'? do I use a book mark? Replace function?
'Get all the sgm files in the directory specified
Dim fndFiles = Directory.GetFiles(searchDir, "*.sgm")
'Set up the regular expression you will make as the condition for the file
Dim rx = New Regex(".*_Ch\d\.sgm")
Dim ch1 = New Regex(".*_Ch[1]\.sgm")
'Use path.combine for concatenatin directory together
'Loop through each file found by the REGEX
For Each fileNo In fndFiles
If rx.IsMatch(fileNo) Then
If ch1.IsMatch(fileNo) Then
Dim result = Path.GetFileName(fileNo)
'Use path.combine for concatenatin directory together
Dim fileToCopy = Path.Combine(searchDir, result)
'This is the file we want to copy into MasterBuild but at specific location.
'match &ch1.sgm inside strMasterDoc
Dim fileContent = File.ReadAllText(fileToCopy)
'Search master file for entity match then append all content of fileContent
File.AppendAllText(existingFileMaster, fileContent)
MessageBox.Show("File Copied")
End If
End If
Next
Close()
End Sub

If I understand correctly (big if), you want to replace the the text of the abbreviated chapter name in the master file with the contents of the file it refers to at the spot where the abbreviation is found.
I made a class to handle the details.
Private Sub btnImport_Click(sender As Object, e As EventArgs) Handles btnImport.Click
'Add a FolderBrowseDialog to your form designer
FolderBrowserDialog1.ShowDialog()
Dim searchDir As String = FolderBrowserDialog1.SelectedPath
Dim existingFileMaster = Path.Combine(searchDir, "Bld1_Master_Document.sgm")
Dim lstFileChanges = CreateList(searchDir)
'The following method does NOT return an array of lines
Dim strMasterDoc = File.ReadAllText(existingFileMaster)
For Each fc In lstFileChanges
strMasterDoc = strMasterDoc.Replace(fc.OldString, fc.NewString)
Next
File.WriteAllText(existingFileMaster, strMasterDoc)
End Sub
Private Function CreateList(selectedPath As String) As List(Of FileChanges)
Dim lstFC As New List(Of FileChanges)
For i = 1 To lstFC.Count
Dim fc As New FileChanges
fc.OldString = $"&CH{i}.sgm"
fc.FileName = $"Chapter{i}.sgm"
fc.NewString = File.ReadAllText(Path.Combine(selectedPath, fc.FileName))
lstFC.Add(fc)
Next
Return lstFC
End Function
Public Class FileChanges
Public Property OldString As String '&CH1.sgm
Public Property FileName As String 'Chapter1.sgm
Public Property NewString As String 'Contents of Chapter1.sgm, the string to insert
End Class
Testing .Replace
Dim s As String = "The quick brown fox jumped over the lazy dogs."
s = s.Replace("fox", "foxes")
MessageBox.Show(s)

Related

How can I ignore a new line character when reading CSV file in VB.NET?

I wrote a utility in VB.NET that reads an input CSV file, does some processing (specifically it ignores the first 5 lines of the input file and replaces them with a header row saved in another file) and writes the information from the input file into a new output CSV file.
Where my program fails is when the input data includes new line characters within one column value within the CSV.
I would like to ignore the new line character within a CSV data row when I load it into my string array.
Here is my code (its embedded in a form)
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim incsvPath = strFileName
Dim outcsvPath = fi.DirectoryName & "\" & outfilename
Dim headerPath = fi.DirectoryName & "\ACTIVITY_HISTORY_HEADER.csv"
Dim fileP As String = incsvPath
Dim fileheader As String = headerPath
Dim CSVheaderIn As New ArrayList
Dim CSVlinesIn As New ArrayList
Dim CSVout As New List(Of String)
CSVheaderIn.AddRange(IO.File.ReadAllLines(fileheader))
CSVlinesIn.AddRange(IO.File.ReadAllLines(fileP))
messageTB.AppendText(vbCrLf & vbCrLf)
For Each line As String In CSVheaderIn
Dim nameANDnumber As String() = line.Split(",")
messageTB.AppendText("csv file header row = " & line & vbCrLf & vbCrLf & "csv file contents follow ..." & vbCrLf)
CSVout.Add(line)
Next
Dim mySubAL As ArrayList = CSVlinesIn.GetRange(5, CSVlinesIn.Count - 5)
For Each line As String In mySubAL 'CSVlinesIn
messageTB.AppendText(line & vbCrLf)
CSVout.Add(line)
Next
IO.File.WriteAllLines(outcsvPath, CSVout.ToArray)
End Sub
This is fairly hard work actually; it'll be easier to use a library that knows how to read and write CSV with newlines in the data than roll your own - not saying you couldn't, but it's a wheel that has already been invented so why do it again?
I used Steve Hansen's Csv - right click your project in solution explorer, choose Manage Nuget Packages, click Browse, Search csv, install the right one
Imports System.Text
Imports Csv
Imports System.IO
Module Module1
Sub Main(args As String())
'open the headers file
Using hIn = File.OpenText("C:\temp\h.csv")
'setup instruction to the csv reader with headersabsent flag so we can get the first line as data
Dim hOptions = New CsvOptions With {.HeaderMode = HeaderMode.HeaderAbsent}
'take the first line into an array - these are our headers
Dim headers = CsvReader.Read(hIn, hOptions)(0).Values
'open the data file,
Using fIn = File.OpenText("C:\temp\a.csv")
'setup instruction for the reader to skip 5 rows, treat first row as data, and allow newlines in quoted fields
Dim fOptions = New CsvOptions With {.RowsToSkip = 5, .HeaderMode = HeaderMode.HeaderAbsent, .AllowNewLineInEnclosedFieldValues = True}
Using fOut = File.CreateText("C:\temp\a_out.csv")
'convert the ICsvLine rows in the reader to rows of String() that the writer will accept, and write them under the headers
CsvWriter.Write(fOut, headers, CsvReader.Read(fIn, fOptions).Select(Function(line) line.Values))
End Using
End Using
End Using
End Sub
End Module
You don't have to use this lib to read the headers; you could just file.ReadText().ReadLine().Split(","c) it
If you want to perform per-line processing on the elements, do this:
CsvWriter.Write(fOut, headers, CsvReader.Read(fIn, fOptions).Select(Function(line) ProcessLine(line.Values)))
...
Function ProcessLine(input As String()) As String()
'Note: If(input(8), "") returns input(8) unless it is nothing in which case "" is returned instead
If If(input(8), "").Length > 10 Then input(8) = input(8).Remove(10) 'Trim if over 10
If If(input(14), "").Length > 10 Then input(14) = input(14).Remove(10)
Return input 'Always return
End Function

VB Parse a text file, match column 1 to a variable, pass column 2 to another variable

I've written a script that will take a table out of a program, and export it to the local drive in a comma delimited text file. What I need is a script to read the text file. The user will input a string in a text box from Public Class Form 1, then the string gets passed to another Sub in Public Class SpaceMenuClass. The handoff looks ok, but I can't figure out how to parse the text file (match column 1 with the string, and store column 2 from that line to pass back to the SpacemenuClass). I know this may seem ambiguous, but hopefully makes some sense. Thanks to anyone in advance.
From Form1 Class
Private Sub BtnPlano_Click_(sender As Object, e As EventArgs) Handles BtnPlano.Click
If TxtBoxPlano.Text <> "" Then
SpaceCommands.SearchPlano(TxtBoxPlano.Text)
Else MessageBox.Show("Please Enter a Valid Planogram Name!")
End If
TxtBoxPlano.Clear()
End Sub
From SpaceMenuClass:
Public Sub SearchPlano(PlanoName As String)
For Each Plano As Space.Planogram In SpacePlanning.ForPlanograms()
SpacePlanning.SetActivePlanogram(Plano.Number - 1)
'Go open the Searchplano table on the shared drive
SpacePlanning.OpenTableChartView(AnalysisFileName:="\\SERVER1\JDA\Tables\SearchPlano.pst")
'Export the table to a Tab Delimited Text file
SpacePlanning.ExportTableData(ExportFileName:="C:\Temp\JDA\SearchPlano.txt", ExportMethod:=ExportMethod.CommaSeparated, UseCurrency:=False, UseQuotedStrings:=False, UseThousandsSeparator:=False)
'Close the Table
SpacePlanning.CloseTableChartView(AnalysisFileName:="\\SERVER1\JDA\Tables\SearchPlano.pst")
' Open the text file and parse it
Dim str As System.IO.StreamReader = New System.IO.StreamReader(New System.IO.FileStream("C:\Temp\JDA\SearchPlano.txt", System.IO.FileMode.Open))
Dim strline, arr(), Name, Nbr As String
Try
NextLine:
strline = str.ReadLine
arr = strline.Split(",")
Name = arr(0)
Nbr = arr(1)
If Name = PlanoName Then
SpacePlanning.SetActivePlanogram(Plano.Number = Nbr)
GoTo Finish
Else
GoTo NextLine
End If
Catch
End Try
Next
Finish:
My.Computer.FileSystem.DeleteFile("C:\Temp\JDA\SearchPlano.Txt")
End Sub
You open the file for reading, then try to delete it before closing it. This would raise an exception. To avoid this, wrap the StreamReader in a Using block. The End Using automatically disposes of the object (closes the file for you).
Public Sub SearchPlano(planoName As String)
For Each plano As Space.Planogram In SpacePlanning.ForPlanograms()
SpacePlanning.SetActivePlanogram(plano.Number - 1)
'Go open the Searchplano table on the shared drive
SpacePlanning.OpenTableChartView(AnalysisFileName:="\\SERVER1\JDA\Tables\SearchPlano.pst")
'Export the table to a Tab Delimited Text file
SpacePlanning.ExportTableData(
ExportFileName:="C:\Temp\JDA\SearchPlano.txt", ExportMethod:=ExportMethod.CommaSeparated,
UseCurrency:=False, UseQuotedStrings:=False, UseThousandsSeparator:=False)
'Close the Table
SpacePlanning.CloseTableChartView(AnalysisFileName:="\\SERVER1\JDA\Tables\SearchPlano.pst")
' Open the text file and parse it
Using str = New System.IO.StreamReader("C:\Temp\JDA\SearchPlano.txt")
Dim arr(), name, nbr As String
Do
If str.EndOfStream Then
' didn't find item!!!
End If
arr = str.ReadLine.Split(",")
name = arr(0)
nbr = arr(1)
Loop Until name = planoName
SpacePlanning.SetActivePlanogram(plano.Number = nbr)
End Using
Next
My.Computer.FileSystem.DeleteFile("C:\Temp\JDA\SearchPlano.Txt")
End Sub
I also cleaned up your loop and added a check for EndOfStream, in case you couldn't find a match (this would have thrown an exception too).
Also, changed the StreamReader to just open the file. You had a nested FileStream object in there, which would have required another Using block, and is unnecessary.

Delete entire line if it contains specific word

I also want to display the line containing the word. I want to open an external .txt file and delete any line if it contains a specific string. I have a search and replace at the moment for one word but want the entire line to be removed from the file. Thanks
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim myStreamReaderL1 As System.IO.StreamReader
Dim myStream As System.IO.StreamWriter
Dim myStr As String
myStreamReaderL1 = System.IO.File.OpenText("C:\Users\f1r1a\Desktop\memes.txt")
myStr = myStreamReaderL1.ReadToEnd()
myStreamReaderL1.Close()
myStr = myStr.Substring("fraser", 6)
'Save myStr
myStream = System.IO.File.CreateText("C:\Users\f1r1a\Desktop\memes.txt")
myStream.WriteLine(myStr)
myStream.Close()
End Sub
Well you can do all of that code in two lines
Dim result = File.ReadLines("C:\Users\f1r1a\Desktop\memes.txt").
Where(Function(x) Not x.Contains("fraser"))
File.WriteAllLines("C:\Users\f1r1a\Desktop\memes.txt", result.ToArray)
The IEnumerable extension Where receives, line by line, the sequence produced by File.ReadLines. Each line is processed by Where applying the Contains method and if the line doesn't contains the word searched then it is passed as output to the result variable. In turn the result variable is passed as an array to the WriteAllLines method.
You can get both at once:
Dim file = "C:\Users\f1r1a\Desktop\memes.txt"
Dim lookup = File.ReadLines(file).ToLookup(Function(l) l.Contains("fraser"))
textBoxRemoved.Text = String.Join("|", lookup(True))
File.WriteAllLines(file, lookup(False))

Variable has already been used before and assigned a value

I' am making a bot for my assignment which uses proxy to browse websites. I have field called "Browse" which lets me browse for the proxy file and reads into an array and shows the total number of proxy from the counter. I' am stuck here in the following. The following are the code that am currently using. Please help
Variable proxyArray has already been used before and assigned a value. A null
reference exception could result at runtime.
Code
Private Sub browserProxy_Click(sender As Object, e As EventArgs) Handles browserProxy.Click
Dim myStream As Stream = Nothing
Dim selectedFile As String
Dim openFileDialog1 As New OpenFileDialog()
Dim proxyArray() As String
Dim totalProxy As Integer
openFileDialog1.InitialDirectory = "C:\"
openFileDialog1.Filter = "Text File (*.txt)|*.txt"
openFileDialog1.FilterIndex = 1
openFileDialog1.RestoreDirectory = False
If openFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
selectedFile = String.Format(openFileDialog1.FileName)
Dim objreader As New System.IO.StreamReader(selectedFile)
i = 0
Do While Not objreader.EndOfStream
proxyArray(i) = objreader.ReadLine
i += 1
Loop
totalProxy = i
objreader.Close()
End If
End Sub
This pops up during runtime.
The compiler is right, you have declared the variable proxyArray but you never initialize it. This is an initialized array with 10 strings that are Nothing
:
Dim proxyArray(9) As String
But since the number of items is unknown you should use a List(Of String) anyway. It is resizable whereas an array has a fixed size.
Dim proxList As New List(Of String)
'...'
proxList.Add(objreader.ReadLine)
If you need an array you can use proxList.ToArray() at the end.
Either use a List(Of String), or ReDim Preserve proxyArray(i + 1) each time.

Vb.Net - Copy files based on pattern

I have got table named FILELISTS
Table Name - Filelists
Field - FileNames
Data Value
File1.txt
File2.csv
File3*.csv
I'm struggling to write the code, as per above if it has a file name (like file1.txt and file2.txt) it needs to copy from source to destination. If file name is pattern (like File3*.csv) then copy all files that matches this pattern from source to destination.
I'm enumerating through above row in Vb.net using data reader.
You can use Directory.EnumerateFiles and File.Copy, for example:
var filePatterns = database.GetFileNamePattern(); // your method that returns the list of files
// assuming you've stored the source- and dest.-directories in the app-settings
string sourceFolder = Properties.Settings.Default.SourceFolder;
string destFolder = Properties.Settings.Default.DestinationFolder;
foreach (string pattern in filePatterns)
{
var files = Directory.EnumerateFiles(
sourceFolder,
pattern,
SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
File.Copy(file, Path.Combine(destFolder, Path.GetFileName(file)), true);
}
}
Edit: Sorry, here the VB.NET version:
' your method that returns the list of files:
Dim filePatterns = database.GetFileNamePattern()
' assuming you've stored the source- and dest.-directories in the app-settings
Dim sourceFolder As String = My.Settings.SourceFolder
Dim destFolder As String = My.Settings.DestinationFolder
For Each pattern As String In filePatterns
Dim files = Directory.EnumerateFiles(sourceFolder, pattern, SearchOption.TopDirectoryOnly)
For Each file As String In files
IO.File.Copy(file, IO.Path.Combine(destFolder, IO.Path.GetFileName(file)), True)
Next
Next
DirectoryInfo, FileInfo - - You deleted your other question before I could click post... but this works with .net framework 2.0, like you asked
Option Strict On
Imports sO = System.IO.SearchOption
Imports dI = System.IO.DirectoryInfo
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For Each F In (New dI("C:\")).GetFiles("*.*", sO.TopDirectoryOnly)
MsgBox(F.FullName)
'Do your copy here
Next
End Sub
End Class