VBA String pattern PinPointing - vba

Ok so i have these 6 which are coerced during Running-time as String Values. So these lines below are String values
bdx-20131231.xml
bdx-20131231.xsd
bdx-20131231_cal.xml
bdx-20131231_def.xml
bdx-20131231_lab.xml
bdx-20131231_pre.xml
inside a macro we have a small simple loop that iterates and prints on the immediate window the string values that end with ".xml" so the xsd (second one) is not printed by the loop. Following you can see the loop
For Each el In IE.Document.getelementsbytagname("a")
If el.href Like "*.xml" Then
Debug.Print el.innertext, el.href
End If
next el
So we are left with these
bdx-20131231.xml
bdx-20131231_cal.xml
bdx-20131231_def.xml
bdx-20131231_lab.xml
bdx-20131231_pre.xml
However what i am trying to nail here is the XBRL INSTANCE DOCUMENT which has no letters at the end of it's naming it's bdx- numbers_only so it's the first one that interests us only.
However the statement... Like "*.xml" grabs and prints both 5 in the immediate window.
The first thing that came to my mind is ok split in two the bdx-20131231.xml and use the function IsNumeric on the second part after the hyphen however the value is coerced.
How can we make the loop pick only the first one bdx-20131231.xml?
For reasons of completeness you can see the whole code which the loop comes from here.
Courtesy of Tim Williams

The below should work:
Like "*[0-9].xml"

Related

Range accepts sometimes only semicolons instead of commas

I have reduced my problem to the following code example. I am using a German Excel version in which separators in normal Excel formulas are semicolons ";" instead of "," (e.g. =SUMME(A1;A3) instead of =SUM(A1,A3)).
Now the code which works different from time to time:
Sub CommasDoNotWorkAnymore()
Dim a()
Dim i%
a = Array("A1,A3,A5", "B1", "B2")
i = 0
Debug.Print Sheets(1).Range(a(i)).Address
End Sub
Normally, when starting Excel, this code works. But sometimes Excel seem to switch the accepted separators used in the Range() to semicolons untill I restart Excel. This occurs most times when rerunning the code after a runtime error.
Is this a general Excel bug? Does anybody know what is behind this behaviour? Is there some Excel-wide "local option" for the Range class?
EDIT: I just tried to convert the a(i) with CStr(a(i) but this does also not work. So no ByRef kind of problem...
If you want to control it, check first what separator is currently in use. What I guess is that you want to know the list separator:
Application.International(xlListSeparator)
Check other separators here:
https://msdn.microsoft.com/en-us/vba/excel-vba/articles/application-international-property-excel
The other time I had a problem with identifying decimal separator in VBA. Finnally I was able to get it in this way:
Function GetVBAdecimalSep()
Dim a(0) As Variant
a(0) = 1 / 2
GetVBAdecimalSep = Mid(a(0), 2, 1)
End Function
Changing separator not always works. Please see this: Changing decimal separator in VBA (not only in Excel)
The best solution is to check/change locale, even temporary.
Application.LanguageSettings.LanguageID(msoLanguageIDUI)
gives the LCID which would be 1033 for English (US)

Deleting Blank Pages in Word Doc with VBA

Trying to write a function to delete blank pages in a Word doc. Nothing gets deleted. I appreciate it if somebody can take a look.
Public Function DeleteBlankPages(wd As Word.Document, wdApp As Word.Application)
Dim par As Paragraph
For Each par In wd.Paragraphs
If IsEmpty(par.Range.Text) Then
par.Range.Select
wdApp.Selection.Delete
End If
Next par
End Function
Look up the definition of IsEmpty in the VBA language reference. It doesn't do what you imagine.
The correct way to find out if there is textual content is to check the number of characters. In VBA, this is typically done with the function Len (=length). You'd think that it the comparision should be to 0 (zero), but that's not the case for a paragraph, because a Word paragraph always contains it's paragraph mark (ANSI 13).
Also, no need to select the paragraph or range in order to delete it, just use the Deletemethod directly on the par.Range. (Which means you also don't need to pass a Word.Application object.
Also note that your code doesn't do anything to pages, only to paragraphs... It could deleted empty pages, depending on how things are formatted, but it might be wise to rename the Function and comment how it's supposed to work.
So more like this:
Public Function DeleteBlankPages(wd As Word.Document)
Dim par As Paragraph
For Each par In wd.Paragraphs
If Len(par.Range.Text) <= 1 Then
par.Range.Delete
End If
Next par
End Function

VB.net Find And Replace from Data in a DataGridView in a text file

Im sure someone out there can help, im totally new to coding but getting into it and really enjoying. I know this is such a simple question out there for you folks but i have the following, I load a spread sheet of strings (2 columns) into a datagridview the reason i do this because there is over 100,000 find and replaces and these will generally sit within and existing string when searching, then from there i want to simply search a txt file and find and replace a number of strings in it. So it would check each row in a datagrid take from column 1 the find and use column 2 to replace then outputs the string to another txt file once the find and replace has taken place. My current results are that it just takes what was in the first file and copies without replacing in the second find.
Any assistance is gratefully received, many thanks.
Please see below my amateur code:-
Private Sub CmdBtnTestReplace_Click(sender As System.Object, e As System.EventArgs) Handles CmdBtnTestReplace.Click
Dim fName As String = "c:\backup\logs\masterUser.txt"
Dim wrtFile As String = "c:\backup\logs\masterUserFormatted.txt"
Dim strRead As New System.IO.StreamReader(fName)
Dim strWrite As New System.IO.StreamWriter(wrtFile)
Dim s As String
Dim o As String
For Each row As DataGridViewRow In DataGridView1.Rows
If Not row.IsNewRow Then
Dim Find1 As String = row.Cells(0).Value.ToString
Dim Replace1 As String = row.Cells(1).Value.ToString
Cursor.Current = Cursors.WaitCursor
s = strRead.ReadToEnd()
o = s.Replace(Find1, Replace1)
strWrite.Write(o)
End If
Next
strRead.Close()
strWrite.Close()
Cursor.Current = Cursors.Default
MessageBox.Show("Finished Replacing")
End Sub
1. What you are doing is :
creating a StreamReader whose purpose is to read chars from a File/Stream in sequence.
creating a StreamWriter whose purpose is to add content to a File/Stream.
then looping
a) read the remaining content of file fName and put it in s
b) replace words from s and put the result in o
c) add o to the existing content of the file wrtFile
then the usual closing of the stream reader/writer...
But that doesn't work because, on the secund iteration of the loop, strRead is already at the end of your loaded file, then there is nothing to read anymore, and s is always an empty string starting from the secund iteration.
Furthermore, because s is empty, o will be empty aswell.
And last of all, even if you manage to re-read the content of the file and replace the words, strWrite will not clear the initial content of the output file, but will write the resulting replaced string (o) after the previously updated content of the file.
2. Since you loaded the content of the file in a string (s = strRead.ReadToEnd()), why don't you :
load that s string before the For-Next block
loop the datagridview rows in a For-Next block
replace using the pair Find1/Replace1 s = s.Replace(Find1, Replace1)
then, save the content of s in the targeted file outside the For-Next block
3. However, improving your understanding of how streams work, what should be considered and what are forbidden is a bit outside the scope of SO I think; such documentation could be found/gathered on the MSDN page or with the help of your friend : google. The same applies for finding out/thinking of how you should arrange your code, how to achieve your goal.Let's take an example :
' Content of your file :
One Two Three Four Five Six
' Content of your DataGridView :
One | Two
Two | Three
Three | Four
Four | Five
Five | Six
Six | Seven
The resulting replacement text at the end of a similar routine as yours will be :
Seven Seven Seven Seven Seven Seven ' :/
' while the expected result would be :
Two Three Four Five Six Seven
And that's because of the iteration : already replaced portions of your file (or loaded file content) could get replaced again and again. To avoid that, either :
split the loaded content in single words, and use a "replaced" flag for each word (to avoid replacing that word more than once)
or preload all the pair Find/Replace, and parse the file content in sequence once, replacing that instance when required.
So, before using an interesting object in the framework :
you should know what it does and how it behaves
otherwise -> read the documentation
otherwise -> create a minimalistic test solution which purpose is to brute force testings on that particular object to debunck all its powers and flaws.
So, like I said in 2., move those ReadAllText() and Write() outside the For/Next block to start from and have a look at the resulting output (Ask specific questions in comments when google can't answer) Then if you're OK with it even if issue like the One Two Three example above could occur, then voila ! Otherwise, use google to gather more examples on "splitting text in words" and reformating the whole, have some tries, then get back here if you're stuck on precise issues.

VBA: Why do people include the variable's name in a "Next" statement?

I have always written my For-loops like this:
For foo = 1 to 10
' do something
Next
However, when I read code snippets online, people always do this:
For foo = 1 to 10
' do something
Next foo
I have not noticed any difference between the two, and I can't find any documentation on next statement is more desirable. What is the difference between those two (if any)?
The counter after the Next statement is optional. It used to be required in BASIC-derived languages, but this is no longer the case in VBA.
You can check the VBA reference:
If you omit counter in a Next statement, execution continues as if counter is included. If a Next statement is encountered before its corresponding For statement, an error occurs.
The reason people still add the counter it to increase readability.
It's for when you have multiple for loops.
For example,
For i to j
For k to l
next k
next i
Otherwise, the next is ambiguous. It's not absolutely necessary, as the loop will still work without it, but it's just good practice to have it marked for the sake of anyone else reading your code.

Using a for loop to call consecutive variable names (ie car1, car2.... car10) in VBA

Scenario)
I have seven variables; labelKid1, labelKid2, ...LabelKid3. I'm searching through cells to find ones that are not empty, and then entering the value into the label, starting with labelKid1, and then moving on to the next label.
Question)
Is there a way to us a for loop to go through these variables? By this I mean can I somehow call the variable with something such as labelKid + j , with j being the value of the for loop? This would allow me to march through the labels a lot more easily.
Now, I understand that I could probably do this by putting the labels into an array and using a for loop to call their indicies, but is there a way to do it as I stated above?
No, VBA does not support variable variables (as they are called in PHP). As you said you will need to use a list, dictionary or similar instead.
You can achieve this using UserForm1.Controls("labelKid" & i) Which calls any form control by name associated with UserForm1
So you would need something like this
Sub ControlName()
Dim i As Long
For i = 1 To 10
UserForm1.Controls("labelKid" & i).Value = i
Next
End Sub
Hope this helps!