I would like to find and replace a certain pattern in word using VBA. More specifically I would like to find every instance of "Table" followed by a whitespace followed by one or more digits followed by another whitespace and replace it with "Table", the same number, a period and a tab. I tried using the Find and Replace function of VBA with the "MatchWildcard" property set to true. Finding the pattern has been no problem, however I can't figure out how to replace the text, so that the number stays the same. My idea was to use the same wildcard in the replacement string, but in this case it just spells out the wildcard as text. Therefore my question is whether there is any way to use the matched value in the replacement string.
toFind = "Table [1-9]# " & vbTab
Dim replacementStr As String
replacementString = "Table [1-9]#." & vbTab
myRange.Find.Execute FindText:=toFind, replaceWith:=replacementStr, _
Replace:=wdReplaceAll, MatchWildcards:=True
Should produce: "Table 1 " -> "Table 1. "
Does produce: "Table 1 " -> "Table [1-9]#. "
For further detail on using wildcards see: https://wordmvp.com/FAQs/General/UsingWildcards.htm
toFind = "(Table [1-9])# " & vbTab
Dim replacementStr As String
replacementStr = "\1." & vbTab
myRange.Find.Execute FindText:=toFind, replaceWith:=replacementStr, _
Replace:=wdReplaceAll, MatchWildcards:=True
Related
I have to format a large document for a file that has been created from a PDF which is editable, so I know all the text is there.
The document is a series of tables. In Word the tables look pretty OK, but in some cases where there should be various cells there is just 1 and tabs have been used to align the text. So, it looks good, but if any of the text gets changed then the formatting will get messed up. I would like to have a macro that looks for cells with a tab, selects the cell, counts the number of tabs, divides the cell into the right number of cells and puts the text into the right cell. For example, a cell that contains "text 1 [tab]text 2[tab]text 3" would become 3 cells "text 1", "text 2" and "text 3".
I thought Word would be able to convert the text to a table, but when the text is already in a table it doesn't work.
If anyone has any suggestions as to how I might achieve this, then they would be much appreciated!
My main issue is not knowing how to count how many tabs are in a selection.
This function will return the number of Tabs in the given string.
Function CountTabs() As Integer
Dim Txt As String
Txt = "This is" & vbTab & "a test" & vbTab & "to count Tabs"
CountTabs = Len(Txt) - Len(Replace(Txt, vbTab, ""))
End Function
The tab character - Chr(9) - is replace with nothing and the number of tabs is the difference in character count before and after the replacement. Here is an implementation of the idea in a snippet.
Private Sub Snippet()
Dim Txt As String
Dim Count As Integer
Txt = "This is" & vbTab & "a test" & vbTab & "to count Tabs"
Count = Len(Txt) - Len(Replace(Txt, vbTab, ""))
MsgBox "There are " & Count & " tabs."
End Sub
Of course, how you get the text for the variable Txt is another story and, in the context of this forum, another question. Prophylactically, I advise against using the Selection object, however. Try to use the Range object instead.
I am new to access VBA.
I am trying to add 1 to all numbers in a field that are equal or greater than the value in text box [TP_Bld_OrderNum_Txt].
This is my code:
CurrentDb.Execute "UPDATE TP_Matrix " & _
"SET TP_Matrix.Order_" & Me.TP_Bld_TP_Cbo & " = TP_Matrix.Order_" & Me.TP_Bld_TP_Cbo & "+1 " & _
"WHERE TP_Matrix.Order_" & Me.TP_Bld_TP_Cbo & ">= Me.TP_Bld_OrderNum_Txt"
I get this error:
too few parameters expected 1
I believe it relates to the text box value.
If I replace Me.TP_Bld_OrderNum_Txt with a number, the query works fine.
I have the text box set up as a number.
Why doesn't it recognize its value?
You provided Me.TP_Bld_OrderNum_Txt as a literal (as a fixed string) and not its value:
& ">= Me.TP_Bld_OrderNum_Txt"
Try this instead:
& " >= " & Me.TP_Bld_OrderNum_Txt.Value
Also, it is a good practice to use .Value to explicitely use the value of the control.
So here's what I want to do:
I have a string origStr, which is at the beginning of a line in a Word document. After origStr is an unknown value (e.g. 23 or 2,6)
I want to find that string and replace the value after with another known value, but keep the string.
Example in my Word document:
Diam. diastole, mm: 53
[Running VBA makro where user input is 54,3]
Expected Result:
Diam. diastole, mm: 54,3
Actual result:
Diam. diastole, mm: 54,3 53
So here's what i got:
origStr = LArray(i, j - 1).Caption & ": *"
replStr = LArray(i, j - 1).Caption & ": " & TBArray(i, j).Text
With ActiveDocument.Content.Find
.MatchWildcards = True
.ClearFormatting
.Text = origStr
.Replacement.ClearFormatting
.Replacement.Text = replStr
.Execute Replace:=wdReplaceAll, Forward:=True, Wrap:=wdFindStop
End With
Why isn't my old value being deleted?
Thanks in advance!
Word uses "lazy" pattern matching which is good in this case because otherwise it would just replace the rest of your entire document. Vincent G gave a solution for one word (no more than one space in the rest of the line), here is something more general:
To get Word to replace everything until the end of the line, you need to include the end of the line into the search string. ^l or ^11 is the control code for new line (shift+enter), ^12 is page or section break, ^13 is carriage return.
This is the most "recent" list I found.
So "yourtext*^11" would match everything from "yourtext" until the next new line and so on.
Depending on your formatting, it could be either one of the above so you have to be careful. If you replace "*^12" but your lines end with new line, you will replace the whole paragraph.
To catch all of them, you can group them: yourtext*[^11^12^13] will match everything until the next new line or carriage return. However if we replace that, the end of the line will be replaced as well so we have to include it in the replacement text. How do we know what it was?
We can use () to define a submatch and \1, \2 etc to use these submatches in the replacement text:
origStr = LArray(i, j - 1).Caption & ": *([^11^12^13])"
replStr = LArray(i, j - 1).Caption & ": " & TBArray(i, j).Text & "\1"
Example:
before:
after replacing with origStr = "yourtext*([^11^12^13])" and replStr = "yourtext newtext\1":
Note: These expressions also work with the Find and Replace dialog, just make sure "Use Wildcards" is enabled
Its not really a VBA problem, the same happening in "Find and Replace" dialog.
Replace your original string with:
origStr = LArray(i, j - 1).Caption & ": <*>"
I have a problem while doing a macro in Excel VBA which looks simple but I was not able to find an answer.
What I want is to change a formula depending on a value of a concrete cell; the cell is situated in C7 and can have the text OR or the text AND. The part of the formula is (being CritEUs and CritSKUs String variables):
If CritEUs = "NO" (OR/AND) CritSKUs = "NO" Then .... (whatever)
So I want to change the OR/AND depending on the value in C7, I tried to use INDIRECT but I think it works only with numbers, and also the following (being W the Worksheet variable):
Dim Pattern As String
Pattern = W.Range("C7").Value
If CritEUs = "NO" " & Pattern & " CritSKUs = "NO" Then
But the Excel don't accept me this option.
Could it be that this is not possible?
I would really appreciate any help!
I'd look to handle this in another if statement and then nest the next if statement within like so:
Sub Example()
Dim Pattern As String
Pattern = W.Range("C7").Value
If Pattern = "AND" Then
If CritEUs = "NO" And CritSKUs = "NO" Then
'Do Something'
End If
ElseIf Pattern = "OR" Then
If CritEUs = "NO" Or CritSKUs = "NO" Then
'Do Something'
End If
End If
End Sub
Even if I strongly prefer Gareth's solution, there is a trick for doing what you want (i.e. for evaluating the condition) through the usage of the Application.Evaluate() method. It would be:
If Application.Evaluate(Pattern & "(" & Chr(34) & CritEUs & Chr(34) & "=" & Chr(34) & "NO" & Chr(34) & "," & Chr(34) & CritSKUs & Chr(34) & "=" & Chr(34) & "NO" & Chr(34) & ")") Then
... where the string being an expression such as =AND(whatever = "NO", whateverelse = "NO") or =OR(whatever = "NO", whateverelse = "NO") (depending on the value of the variable Pattern) that can be evaluated by the MS Excel application no matter what the system language is.
But as I said, I would personally prefer a nested if block as Gareth suggested because it's clearer what you are doing and it cannot crash if the user inserts an invalid logic operator or makes just a spelling mistake; you should consider this option if you don't want / cannot slightly re-design your code.
FORMULA EXPLANATION - required from the asker
The Evaluate() is a method of the Application object, which means of the object MS Excel. This method is very straightforward:
input: string
output: evaluation of the string
It is in fact used to "evaluate" a string inserted by the user exactly as it does when you type a formula into a cell. If you type into a cell "=3+4", you are basically typing Application.Evaluate("3+4"). This will return you 7, because it's the result of the string evaluation you provided.
This built-in is very very powerful, because it uses a very consolidated system (the one of MS Excel) to parse and evaluate any string that Excel can evaluate. Moreover, the evaluation is always in English (you can use the English function IF but not the Italian SE, nor the German WENN or the French SI because the method evaluates as if your Excel was in English to be system independent.
On the other hand, the Chr(34) is just returning the character ". This character is hard to use in VBA because it's usually need to separate strings (e.g. a = "first" & "second". However, you need this character inside the string to be evaluated so I'm just calling it with Chr(34) to avoid confusion of the compiler.
SUMMARY:
The string is being built up like this:
Pattern & "(" & Chr(34) & CritEUs & Chr(34) & "=" & Chr(34) & "NO" & Chr(34) & "," & Chr(34) & CritSKUs & Chr(34) & "=" & Chr(34) & "NO" & Chr(34) & ")"
Being...
Pattern = AND or OR
Chr(34) = "
... the string that we are building will be of this kind (just a possible outcome):
"AND("NO"="NO","YES"="NO")"
So, once we have built-up this string, we pass it into the Evaluate method: it's like if we were writing =AND("NO"="NO","YES"="NO") into an Excel cell. What would the outcome be? Clearly it depends on your variable, but in this case it would be FALSE, so the If - Then block will not be entered because the return value is false. Otherwise, it would be entered.
This is not a "wrong" method, but as I was saying it has only two possible downsides:
1) It needs data validation, because if you pass crap into the variable Pattern the Evaluate method will fail; in Gareth's solution, instead, only AND and OR will be evaluated, otherwise the code will skip --> more stability;
2) It's not 100% intuitive: while Gareth's solution could be explained to a 10 year old child (because it's very very straight-forward to understand), this one needs (as we just did) a deeper analysis to understand properly what it does. I.E.: you need one line of code to write it, but you/someone else that will have to work on it in the future will need 5-10 minutes and a cup of coffee to understand what the statement wants to check.
I'm using Excel to generate a summery report for my data. I want each summery to be displayed in a single cell. I used VBA and I got something like this:
I want to be able to display the data like this:
All the lines should start with "Increase" or "Decrease". How can I do it in VBA? (I have many cells like the one in this example) how to go over a text inside a specific cell and add a new line after each of these words?
If you are trying to fix the macro so it formats the lines correctly in future then you you need to add in a line feed (I use CrLf myself but Excel, for cells, only cares about the Line Feed) by concatenating the elements with vbLf.
My thanks to #retailcoder for pointing out that vbNewLine == vbCrLf, so you can use whichever makes more sense to you.
so something like Range.Value = "line 1" & vbcrlf & "line 2" & vbcrlf & "line 3" etc:
Range.Value = _
"line 1" & vbcrlf & _
"line 2" & vbcrlf & _
"line 3"
or, personally, I prefer to construct the text through a loop or using Join():
Range.Value = Join(Array( _
"Line 1", _
"Line 2", _
"Line 3"), vbCrLf)
For it to actually display on new lines, you need to double check that Word Wrap is on (Excel will set it on automatically but just in case it has been overridden by something else) using Range.WrapText = True
However, I realise an interpretation is that you just want to quickly fix what is already on the sheet. If this is the case then just manually do a Find and Replace of the word "Increase" or "Decrease" with Char(10)Increase or Char(10)Decrease respectively, where Char(10) is what you can get by pressing Alt+Numpad 0010, or by pasting in the value of the result from the formula =CHAR(10). Then remove the first character using a formula.