Keep trailing zeros when pasting a double to an external application - excel

I am working on a VBA program which should update some decimal numbers in text fields of another application. The numbers are contained in the range P6:P18 of the worksheet "FX Rates".
My problem is that any trailing zeros are not kept when pasting to the external application. For example, 3.1640 becomes 3.164, which is an invalid value in my case.
A snip of my current setup (only showing one Dim of 18 Ranges with decimal numbers) is shown in the block below. My expectation was that any trailing zeros would be kept when pasting to the external app.
Sub UpdateExchangeRateCuts()
Dim USDDKK As Range: Set USDDKK = Worksheets("FX Rates").Range("P6")
InitializeExternalApp
PasteXY 9, 47, USDDKK
I use a Public Sub (InitializeExternalApp) which basically inserts USDDKK in a text field of another application. This procedure works fine, but any trailing zeros are not kept. I have tried to use NumberFormat in the following way:
Sub UpdateExchangeRateCuts()
Dim USDDKK As Range: Set USDDKK = Worksheets("FX Rates").Range("P6")
USDDKK.NumberFormat = "0.0000"
InitializeExternalApp
PasteXY 9, 47, USDDKK
This does not work, however.
I would highly appreciate any tips on how to keep the trailing zeros. Thanks!

Try this:
Dim USDDKK As String
USDDKK = Format(Worksheets("FX Rates").Range("P6").Value, "0.0000")
InitializeExternalApp
PasteXY 9, 47, USDDKK

Related

Pushing data from Excel to Word throws error 5844 when text contains apostrophe

My Excel macro reads the values of a bunch of cells in Excel and pushes them to corresponding "content controls" in a Word template file. Everything works as planned unless the source cell contains a string with an apostrophe, e.g. "Children's Hospital". In this case execution stops:
"Run time error 5844 One of the values to this method or property is incorrect".
I have tried to read the cell value into an auxiliary string variable before assigning that to the content control but that did not help.
I also tried to force the source value to string using the CStr function - no good.
What do I do wrong?
Help please.
Sub PushToWord()
Dim oAppWord As Word.Application
Dim oDoc As Word.Document
...
With ThisWorkbook.Worksheets("Results")
...
oDoc.SelectContentControlsByTitle("Institution").Item(1).Range.Text = .Cells(18, iSCol).Value
...
End With
...

Indent a string by 4 spaces (Add Tab to string)

I am trying to add indentation to a string, essentially adding 4 spaces in front of each line in the string. The string that I want to add the indentation to is called StringToIndent.
Public Class ModifyPage
Private Sub Button_Test_Click(sender As Object, e As RoutedEventArgs) Handles Button_Test.Click
Dim StringToIndent As String = ("This is the first row
This is the second row
This is the third and final row in MyString")
Dim MySecondString As String = "This is a string in one line."
Dim BothStringsTogether = StringToIndent & Environment.NewLine & MySecondString
Debug.Write(BothStringsTogether)
End Sub
End Class
The current output:
This is the first row
This is the second row
This is the third and final row in MyString
This is a string in one line.
I want the final code (that is indented) to output:
This is the first row
This is the second row
This is the third and final row in MyString
This is a string in one line.
How can this be achieved through code? Is there a formatting option that allows me to add indentation? A method that doesn't require me to loop through a string and adding four spaces for each line would be preferable.
Edit: A way to achieve the expected output is to replace the new line with a new line and then add the indent. However, there must be a more elegant way of doing it?
Code:
Dim StringToIndent As String = ("This is the first row
This is the second row
This is the third and final row in MyString")
Dim indentAmount = 4
Dim indent = New String(" "c, indentAmount)
StringToIndent = indent & StringToIndent.Replace(Environment.NewLine, Environment.NewLine & indent)
Debug.Write(StringToIndent)
Maybe something like:
Dim res as String
Dim parts As String() = StringToIndent.Split(ControlChars.CrLf.ToCharArray)
For Each part As String In parts
res.Append(" ") & part & vbCrLf
Next
In C# you can mark the String as a verbatim string literal by prefixing the literal with the # symbol.
In VB.NET we don't have this option. Instead, a workaround would be to create an XML literal and get the value. Here is an example:
Dim input As String = <element> This is the first row
This is the second row
This is the third and final row in MyString
This is a string in one line.
</element>.Value().ToString()
Debugger.WriteLine(input.ToString())
If the value is not static, e.g. you're getting it from somewhere, then you're forced to iterate through the String in some form. You can either Replace like in your example, do a Split and Join (similar to your example), or you'll need to manually iterate.
The manual iteration could look more elegant using LINQ, but you don't gain anything from it.
The bottom line is that if your String is static then you can use the XML literal example I provided, otherwise if the String is dynamic then your solution is perfectly appropriate.
UPDATE
As Andrew Morton pointed out, multiple line String literals have existed since Visual Studio 2017. The following would produce the same outcome as my XML literal example:
Dim input As String = " This is the first row
This is the second row
This is a string in one line"
Debugger.WriteLine(input)
Using an interpolated string indicated by the $ preceeding the string and the vb constants.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim s = $"{vbTab}This Is the first row{vbCrLf}{vbTab}This Is the second row{vbCrLf}{vbTab}{vbTab}This Is the third And final row in MyString{vbCrLf}This Is a string in one line."
Debug.Print(s)
End Sub

Some doubts about Dim and Set Worksheet

Normally, Dim should be done first and then Set should be done in vba code, like the below code.
Dim xWs1 As Worksheet
Dim xWs2 As Worksheet
.
.
.
Dim xWsN As Worksheet
Set xWs1 = Worksheets("A")
Set xWs2 = Worksheets("B")
.
.
.
Set xWsN = Worksheets("NNN")
If I need to Dim and Set 5 worksheets, 10 lines of code will be needed. It seems that the code will be too long when I need to Dim and Set more than 5 worksheets.
I found that if I just use Set, the vba code can also run properly. I would like to ask this will cause any problems if I didn't use Dim?
Set xWs1 = Worksheets("A")
Set xWs2 = Worksheets("B")
.
.
.
Set xWsN = Worksheets("NNN")
Thanks!
If you don't use dim statement , variable is automatically created as a Variant type.
The Variant type can be an integer, a string, a workbook, or any of the other type of variable and it can change as the variable changes, one moment it can be a string, then it can be changed to a workbook.
Using Dim
Without using Dim
There are mainly two problems with not using Dim,
Variant types uses more computer memory as a result it will make your code slow especially when you use loops.
Difficult to find errors ( in your case you can assign anything to variable XWs1 such as numbers , names etc. which can be avoided if you use dim)
How to Declare and Set 92 Objects using 92 Characters:
If "taking up space" is your concern, and you hypothetically want to explicitly set 5 procedure-level variables (w1..w5) to Set to 5 worksheets (Sht1..Sht5), you could use:
Example #1:
DefObj W
Sub wSet1()
Dim w1, w2, w3, w4, w5
Set w1=[Sht1]:Set w2=[Sht2]:Set w3=[Sht3]:Set w4=[Sht4]:Set w5=[Sht5]
End Sub
...or, even more space-efficient, if for example, you had 92 worksheets to Set in 92 declared variables? Then:
Example #2:
DefObj W
Sub wSet2():Dim wks(1To 92),x:For x=1To 92:Set wks(x)=Sheets("Sht"&x):Next x:End Sub
(That's 92 characters... not counting the line feed!)
Explanation:
Between these two ways of shortening declaration, we're using six shortcuts. Below is a summary of each, and see the links under "More Information" for full documentation on each.
Disclaimer: There are a number of reasons we shouldn't use shortcuts in programming. The obvious one is that, the more you compress code, the harder it is to read and understand (especially by others), and therefore can be harder to troubleshoot or expand upon.
If you don't know what the "standard methods" are, do not learn the shortcuts first! Learn how to do things "THE RIGHT WAY" before learning the shortcuts, no matter how appealing it may seem. There was a time that I argued that neatness like indentation and commenting, and full, proper techniques, didn't matter. I was wrong; had to learn that the hard way. If you're reading this, you'll probably have to learn the hard way too, but at least:
Don't use shortcuts when posting example code in your Stack Overflow questions. (This is not a method of [MCVE]!) You will probably get yelled at! ...and possibly have you questions down-voted or ignored... You were warned!
✓ DefObj (Default Data Types)
[Deftype statements][1] are a forgotten method of declaring default data types. Normally, the default data type is [`Variant`][2], so this:
Dim myVariable as Variant
...is identical to:
Dim myVariable
...however the DefObj W statement (used at module-level) says:
All variables declared in this module, that start with the letter 'W' default to type Object (unless otherwise specified). Note that Deftypes statements must be used at module-level (before your first Sub).
The entire list: (More Info)
DefBool DefByte DefCur DefDate DefDbl DefDec DefInt DefLng DefSng DefStr DefObj DefVar
✓ , (Commas in 'Dim' Statements)
When declaring variables with Dim, multiple variables can be listed on the same line, separated with a comma. Therefore this:
Sub mySub()
Dim myVariable1 as Currency
Dim myVariable2 as Currency
…
...is identical to this: (combining examples with Deftypes)
DefCur m
Sub mySub()
Dim myVariable1, myVariable1
…
✓ Sheets ('Sheets' collection)
The WorkSheets Object refers to the collection of all the Worksheet objects in the specified or active workbook.
The Charts Object` refers to the collection of **all the Chart objects in the specified or active workbook.
But the **Sheets Objectrefers to ***both*** theWorksheets*and*Charts` collections.
So, if a workbook has 3 worksheets and 2 chart sheet, in VBA:
Sheets.Count will return 5
Worksheets.Count will return 3
Warning: Using Sheets could cause a conflict if you have a Chart and a Worksheet with the same name (and should also be avoided when referring to worksheets in other files). But for a simple single-file, worksheet-only workbook, save yourself some Work and stick with just Sheets.
✓ [ ] (Square-Bracket Reference Shortcuts)
[Square brackets] can be used as a shortcut when referring to Worksheets, Cell Ranges and individual Cells. You can use either the A1 Reference Style or a named range within brackets as a shortcut for the Range property. You do not have to type the word "Range" or use quotation marks.
Worksheets("Sheet1").[A1:B5].ClearContents
[MyRange].Value = 30
This is barely documented, and even less documented is the fact that, if used in the logical order, square brackets can be used to refer to worksheets.
Combining examples, all of these statements will have identical result:
Worksheets("Sheet1").Range("A1") = Now()
Sheets("Sheet1").Range("A1") = Now()
Worksheets("Sheet1").[A1] = Now()
Sheets("Sheet1").[A1] = Now()
[Sheet1].[A1] = Now()
✓ wks() (Variable Arrays)
If you have a large number of similar objects to declare, it's often easier (and more organized) to group them together in an array. An array can be declared as any type including, for example, Object, Worksheet. (...or even the rarely-used and bizarre types like LongLong and IConverterApplicationPreferences. (Apparently whoever thought up that one doesn't care for shortcuts.)
✓ For..Set..Next (Loop to Set Variable Arrays)
When using an array of objects (any any variable sets), the next logical step is to reduce code with any tasks that need to be performed on the entire group of objects.
Other Notes:
Example #1 could have been compressed to one line but I wanted it to be easy to read in the answer. If our sheet names were S1..S5 instead of the oh-so-lengthy Sht1..Sht5, and we use the :, we could accomplish the same thing in 105 characters:
Example #1b:
DefObj W
Sub wSet():Dim w1,w2,w3,w4,w5:Set w1=[S1]:Set w2=[S2]:Set w3=[S3]:Set w4=[S4]:Set w5=[S5]:End Sub
Data Type Shortcut Symbols
Another rarely used set of dates back to 1974: data type shortcuts chosen by Gary Kildall for the CP/M Operating System
Symbol  Data Type  Constant                                                            
% Integer vbInteger = 2
$ String vbString = 8
& Long vbLong = 3
# Decimal vbDecimal = 6
! Single vbSingle = 4
# Double vbDouble = 5
Still supported today in many coding languages, you could for example use these interchangeably:
Dim myVariable as String
Dim myVariable$
More Information:
Microsoft.com : How to Break and Combine Statements in Code (VB/VBA)
MSDN : Refer to Cells by Using Shortcut Notation
Excel Hero : Excel VBA Shortcut Range References
MSDN : Using Data Types Efficiently
MSDN : Dim Statement (VBA)
ExcelHowTo : Worksheets vs. Sheets
Stack Overflow : Difference between Worksheets & Worksheet objects
MSDN : Set Statement
MSDN : Declaring Arrays
Take the following example of why using implicit variable declaration is usually a bad idea:
Sub Test()
myVariable = 10
myOutcome = myVaraible + 5
End Test
myOutcome = 5. Can you see why?
I misspelled myVariable in the second line, so I just essentially created a brand new variable myVaraible (which had a default value of 0).
This is why you should always use Option Explicit at the beginning of every module; and why you should always explicitly declare all variables.
While it still works, you are just setting yourself up for needless debugging headaches.
If your issue is that you want to condense your code to use less lines, you can do something like this:
Option Explicit
Sub Test()
Dim myVariable As Long: myVariable = 10
Dim myOutput As Long
myOutput = myVariable + 5
End Sub
You can also declare multiple variables on the same line:
Option Explicit
Sub Test()
Dim myVariable As Long, myOutput As Long
myVariable = 10
myOutput = myVariable + 5
End Sub
Not necessarily recommending this (as it can degrade readability), but it's yet another method of declaring variables. This does require the same data type, but you can add your worksheets in an array (from your example):
Option Explicit
Sub Test()
Dim xWs(1 To 5) As Worksheet
Set xWs(1) = Worksheets("A")
Set xWs(2) = Worksheets("B")
Set xWs(3) = Worksheets("C")
Set xWs(4) = Worksheets("D")
Set xWs(5) = Worksheets("E")
End Sub

Finding a certain type of String in Visual Basic and replacing it

I'm currently trying to automate our accounting process. From the bank, I download a .csv file that I'd like to transform in a certain way. I'm also attempting to eliminate all IBAN and BIC numbers from the document as they're not necessary for the accounting process.
Now, every IBAN and BIC follows a certain pattern. How do I replace all strings with a certain pattern (i.e. XX00000000000000 and DEXXXXXXXXX) or at least how do I find them using Visual Basic? I'm familiar with the .replace method already, I just cannot manage to find the string.
Thank you so much in advance!
I think this should help you:
RegEx
An another way could be to load each textline of the .csv file into an array and just Loop through them.
Something like:
Dim Textline() As String 'array
Dim IBAN As String
Dim posIBAN As Integer
Dim iban_length As Integer
textlinelength = UBound(Textline)
iban_length = 22
For i = 0 To textlinelength
If InStr(Textline(i), "DE") Then 'if array contains DE
posIBAN = InStr(Textline(i), "DE") 'find position of IBAN
IBAN = Mid(Textline(i), posIBAN, iban_length) 'get IBAN
Textline(i) = Replace(Textline(i), IBAN, "") 'replace IBAN with ""
End If
Next i
After that you could create a new file and write the arrays in it.
So you would have a IBAN-free txt-file
PS: Is there a way to properly link other questions/answers?

VBA split string into substrings from file directory

I've searched for this topic a lot but haven't found my exact issue. Also I seemingly can't figure out how to adapt the code samples for my use.
I'm trying to split a "file directory string" into substrings from right to left.
"C:\Users\Me\CustomerName\ProductName\2017\"
And split this from right to left, to
year
productname
customername
My attempts at using Split() to get it working, have always split it in the wrong places.
You mentioned you have tried with Split, so this is a good start:
Option Explicit
Public Sub TestMe()
Dim strFolderString As String
Dim arrFolderString As Variant
strFolderString = "C:\Users\Me\CustomerName\ProductName\2017\"
arrFolderString = Split(strFolderString, "\")
Debug.Print arrFolderString(UBound(arrFolderString) - 1)
Debug.Print arrFolderString(UBound(arrFolderString) - 2)
Debug.Print arrFolderString(UBound(arrFolderString) - 3)
End Sub
The idea is to use UBound as the right to left. I do not start from 0, because your string ends with \, thus the 0th position is empty.

Resources