Passing String to another sub routine [duplicate] - vba

This question already has answers here:
How to make Excel VBA variables available to multiple macros?
(3 answers)
Closed 6 years ago.
I am trying to practice embedding my code. I created a subroutine called JrnlHeader to declare variables I will use in another subroutine. I am currently only concerned with one variable named Header. I would like to know why Header is empty in subroutine PrintToTextFile and how I can fix it to be able to use strings declared in JrnlHeader.
Private Sub JrnlHeader()
Dim Header As String
Dim SeqNo As String
Dim SeqVar As String
Dim Bu As String
Dim BuVar As String
Dim JrnlID As String
Dim JrnlIDVar As String
Dim JrnlDate As String
Dim JrnlDateVar As String
Dim Descr As String
Dim DescrVar As String
Dim Ledger As String
Dim LedgerVar As String
Dim Source As String
Dim SourceVar As String
Dim CurEff As String
Dim Reverse As String
Dim AutoLn As String
Dim AdjEnt As String
Header = "<JRNL_HDR_IMP>"
SeqNo = "<SEQNO>" & SeqVar & "</SEQNO>"
Bu = "<BUSINESS_UNIT>" & BuVar & "</BUSINESS_UNIT>"
JrnlID = "<JOURNAL_ID>" & JrnlIDVar & "</JOURNAL_ID>"
JrnlDate = "<JOURNAL_DATE>" & JrnlDateVar & "</JOURNAL_DATE>"
Descr = "<DESCR254>" & DescrVar & "</DESCR254>"
Ledger = "<LEDGER_GROUP>" & LedgerVar & "</LEDGER_GROUP>"
Source = "<SOURCE>" & SourceVar & "</SOURCE>"
CurEff = "<CUR_EFFDT>" & JrnlDateVar & "</CUR_EFFDT>"
Reverse = "<REVERSAL_CD>N</REVERSAL_CD>"
AutoLn = "<AUTO_GEN_LINES>N</AUTO_GEN_LINES>"
AdjEnt = "<ADJUSTING_ENTRY>N</ADJUSTING_ENTRY>"
End Sub
Sub PrintToTextFile()
Dim FileNum As Integer
JrnlHeader
FileNum = FreeFile ' next free filenumber
'Open "C:\Temp\TEXTFILE.TXT" For Output As #FileNum ' creates the new file
Open "C:\temp\TEXTFILE.TXT" For Append As #FileNum
Print #FileNum, Header
Close #FileNum ' close the file
End Sub

You have defined Header to be a local variable in JrnlHeader. This means its scope does not extend to other subroutines/functions.
You can define the scope of the variable to be "module" level, by placing the Dim Header As String statement prior to the first subroutine/function within the code module. Then its value will be available when execution resumes in PrintToTextFile.
Alternatively, you could change your code to pass the variable as a parameter between the two functions:
Sub PrintToTextFile()
Dim Header As String
'...
JnrlHeader Header
'...
Print #FileNum, Header
End Sub
Sub JrnlHeader(Header As String)
'... (but don't include any declaration of Header!)
Header = "<JRNL_HDR_IMP>"
'...
End Sub
But, judging by how many variables are being set up in JrnlHeader, I think you will want to go with using a module-level scoped variable approach.

The two subroutines have different scope. Variables defined JrnlHeader are not available in PrintToTextFile. If you want header to be available in PrintToTextFile the change it to PrintToTextFile(header as string) and call PrintToTextFile(header) from JrnlHeader.

Related

Text file split in blocks vb.net

I am trying to go through my text file and create a new file that will contain only the text I require. My current line looks like:
Car-1I
Colour-39
Cost-328
Dealer-28
Car-2
Colour-30
Cost-234
For each block of text I would like to read the first line, if the first line ends with an I, then read the next line, if that line contains a colour 39, then I would like to save the whole block of text to another file. If these two conditions aren't met, I dont want to save my values to the new text file.
Before anything about saving my values in classes are mentioned, these blocks of text can vary in size and values, so I dont always have a set range of values which is why i need to skip to the blank line
IO.File.WriteAllText("C:\Users\test2.txt", "") 'write to new file
Dim sKey As String
Dim sValue As Integer
For Each filterLine As String In File.ReadLines("C:\Users\test.txt")
sKey = Split(filterLine, ":")(0)
sValue = Split(filterLine, ":")(1)
If Not sValue.EndsWith("I") Then
ElseIf sValue.EndsWith("I") Then
End If
Next
Another method, using File.ReadLines to read lines of text from file. This method doesn't load all the text in memory, it reads from disc single lines of text, so it can also be useful when dealing with big files.
You could loop the IEnumerable collection it returns, but also use its GetEnumerator() method to control more directly when to move to the next line, or move more then one lines forward.
Its Enumerator.Current object returns the line of text currently read, Enumerator.MoveNext() moves to the next line.
A StringBuilder is used to store the strings when a match found. Strings are added to the StringBuilder object using its AppendLine() method.
This class is useful when dealing with strings that you need to store, compare and discard (or modify) quickly: since string are immutable, when you use String variables directly, especially in loops, you generate a whole lot of garbage that slows down any procedure quite a lot.
The blocks of text stored in the StringBuilder object are then written to a destination file using a StreamWriter with explicit encoding set to UTF-8 (writes the BOM). Its methods include asynchronous versions: WriteLine() can be replaced by awaitWriteLineAsync() to allow an async procedure.
Imports System.IO
Imports System.Text
Dim sourceFilePath = "<Path of the source file>"
Dim resultsFilePath = "<Path of the destination file>"
Dim sb As New StringBuilder()
Dim enumerator = File.ReadLines(sourceFilePath).GetEnumerator()
Using sWriter As New StreamWriter(resultsFilePath, False, Encoding.UTF8)
While enumerator.MoveNext()
If enumerator.Current.EndsWith("I") Then
sb.AppendLine(enumerator.Current)
enumerator.MoveNext()
If enumerator.Current.EndsWith("39") Then
While Not String.IsNullOrWhiteSpace(enumerator.Current)
sb.AppendLine(enumerator.Current)
enumerator.MoveNext()
End While
sWriter.WriteLine(sb.ToString())
End If
sb.Clear()
End If
End While
End Using
This will work:
Dim strFile As String = "c:\Test5\Source.txt"
Dim strOutFile As String = "c:\Test5\OutPut.txt"
Dim strOutData As String = ""
Dim SourceGroups As String() = Split(File.ReadAllText(strFile), vbCrLf + vbCrLf)
For Each sGroup As String In SourceGroups
Dim OneGroup() As String = Split(sGroup, vbCrLf)
If Strings.Right(OneGroup(0), 1) = "I" And (Strings.Right(OneGroup(1), 2) = "39") Then
If strOutData <> "" Then strOutData += (vbCrLf & vbCrLf)
strOutData += sGroup
End If
Next
File.WriteAllText(strOutFile, strOutData)
Something like this should work:
Dim base, i, c as Integer
Dim lines1$() = File.ReadLines("C:\Users\test.txt")
c = lines1.count
While i < c
if Len(RTrim(lines1(i))) Then
If Strings.Right(RTrim(lines1(i)), 1)="I" Then
base = i
i += 1
If Strings.Right(RTrim(lines1(i)), 2)="39" Then
While Len(RTrim(lines1(i))) 'skip to the next blank
i += 1
End While
' write lines1(from base to (i-1)) here
Else
While Len(RTrim(lines1(i)))
i += 1
End While
End If
Else
i += 1
End If
Else
i += 1
End If
End While

VB.Net Cant create "new line" "string"

I am in need of assistance... i am trying to create a textfile with links in it. the code i have..
dim domain as string = "http://www.mywebsite/"
dim name as string = "username"
Dim link As String = New String("domain" & "name")
TextBox1.AppendText(link & Environment.NewLine)
Msgbox(textBox1.lines(0))
The problem is that MsgBox only shows up as "http://www.mywebsite/". the textbox does show "http://www.mywebsite/username" but when copied to text document it is:
Line0: http://www.mywebsite/
Line1:username
any ideas... tried using
Dim link As String = String.Join(domain & name) but that doesnt work nor does
Dim link As String = new String.Join(domain & name)
i need
Msgbox(textBox1.lines(0)) to display "http://www.mywebsite/username" not one or the other.
That was quick got a message saying to use. Dim link As String = String.Concat(domain & name)
i think you should move to StringBuilder first import Imports System.Text
'create a string with multiple lines
Dim a As New StringBuilder
a.AppendLine("hi")
a.AppendLine("there")
a.AppendLine("this")
a.AppendLine("is")
a.AppendLine("a")
a.AppendLine("test")
'read will makes read line by line
Dim read As String() = a.ToString.Split(vbNewLine)
'count has number of lines
Dim count As Integer = a.ToString().Split(vbNewLine).Length - 1
'lines will be added to combobox one by one
For i As Integer = 0 To count - 1
ComboBox1.Items.Add(read(i))
Next
you just should edit it to suits your needs i didnt understand what you needed exactly

VB DownloadFile URL variable

I'm attempting to pass a string to the DownloadFile function in Visual Basic in place of the URL. The url will change according to what the current month and year is. Ex: http://example-website.com/092015
For this reason, I've done the following to make sure the url is updated every month:
Public Sub Main()
Dim A As String = "http://example-website.com/"
Dim B As String = Format(Month(Now), "00")
Dim C As String = Year(Now)
Dim registrySite As String = A & B & C
End Sub
The problem that I'm having is, the DownloadFile function requires a string.
Public Sub DownloadFile (
address As String,
destinationFileName As String
)
Is there a workaround for this or another way to do what I'm trying to do? I should note that the website cannot be cached.

Renaming all files in a folder

I'm wondering if it's possible to rename all the files in a folder with a simple program, using vb.NET
I'm quite green and not sure if this is even possible.
Lets say there is a folder containing the files:
Text_Space_aliens.txt, fishing_and_hunting_racoons.txt and mapple.txt.
Using a few credentials:
Dim outPut as String = "TextFile_"
Dim fileType as String = ".txt"
Dim numberOfFiles = My.Computer.FileSystem.GetFiles(LocationFolder.Text)
Dim filesTotal As Integer = CStr(numberOfFiles.Count)
Will it be possible to rename these, regardless of previous name, example:
TextFile_1.txt, TextFile_2.txt & TextFile_3.txt
in one operation?
I think this should do the trick. Use Directory.GetFiles(..) to look for specific files. Enumerate results with a for..each and move (aka rename) files to new name. You will have to adjust sourcePath and searchPattern to work for you.
Private Sub renameFilesInFolder()
Dim sourcePath As String = "e:\temp\demo"
Dim searchPattern As String = "*.txt"
Dim i As Integer = 0
For Each fileName As String In Directory.GetFiles(sourcePath, searchPattern, SearchOption.AllDirectories)
File.Move(Path.Combine(sourcePath, fileName), Path.Combine(sourcePath, "txtFile_" & i & ".txt"))
i += 1
Next
End Sub
In your title you state something about chronologically, but within your question you never mentioned it again. So I did another example ordering files by creationTime.
Private Sub renameFilesInFolderChronologically()
Dim sourcePath As String = "e:\temp\demo"
Dim searchPattern As String = "*.txt"
Dim curDir As New DirectoryInfo(sourcePath)
Dim i As Integer = 0
For Each fi As FileInfo In curDir.GetFiles(searchPattern).OrderBy(Function(num) num.CreationTime)
File.Move(fi.FullName, Path.Combine(fi.Directory.FullName, "txtFile_" & i & ".txt"))
i += 1
Next
End Sub
I've never done Lambdas in VB.net but tested my code and it worked as intended. If anything goes wrong please let me know.

Can I simultaneously declare and assign a variable in VBA?

Can I convert the following declaration and assignment into one line:
Dim clientToTest As String
clientToTest = clientsToTest(i)
or
Dim clientString As Variant
clientString = Split(clientToTest)
There is no shorthand in VBA unfortunately, The closest you will get is a purely visual thing using the : continuation character if you want it on one line for readability;
Dim clientToTest As String: clientToTest = clientsToTest(i)
Dim clientString As Variant: clientString = Split(clientToTest)
Hint (summary of other answers/comments): Works with objects too (Excel 2010):
Dim ws As Worksheet: Set ws = ActiveWorkbook.Worksheets("Sheet1")
Dim ws2 As New Worksheet: ws2.Name = "test"
You can sort-of do that with objects, as in the following.
Dim w As New Widget
But not with strings or variants.
You can define and assign a value in one line, as shown below. I have given an example of two variables declared and assigned in a single line. If the data type of multiple variables are the same:
Dim recordStart, recordEnd As Integer: recordStart = 935: recordEnd = 946
in fact, you can, but not that way.
Sub MySub( Optional Byval Counter as Long=1 , Optional Byval Events as Boolean= True)
'code...
End Sub
And you can set the variables differently when calling the sub, or let them at their default values.
In some cases the whole need for declaring a variable can be avoided by using With statement.
For example,
Dim fd As Office.FileDialog
Set fd = Application.FileDialog(msoFileDialogSaveAs)
If fd.Show Then
'use fd.SelectedItems(1)
End If
this can be rewritten as
With Application.FileDialog(msoFileDialogSaveAs)
If .Show Then
'use .SelectedItems(1)
End If
End With