I'm trying to replace every 10th word in a Word document with underscores equal to the length of the word. This is the code that I've tried so far but it doesn't seem close to working. I'm new to VBA. I feel like I'm able to move between words using the FOR EACH loop but I'm having trouble working the selection object
Sub Macro1()
'
' Macro1 Macro
'
'
i = 0
For Each aword In ActiveDocument.Words
' Selection = aword
i = i + 1
aword.Select
If (i Mod 10) = 0 Then
blanks = ""
For Counter = 0 To Len(aword)
blanks = blanks + "_"
Next Counter
Word.Selection.TypeText (blanks)
aword.Cut
End If
Next aword
End Sub
Also, is VBA the easiest language available for doing something like this in a word processing document? Is there a simpler one? I'm trying to help a student who last coded with Wang VS Glossary Decision Processing language https://en.wikipedia.org/wiki/Wang_Laboratories#Wang_OIS
If you are just starting out, VBA is probably the easiest whenever you are working directly with Microsoft Office documents. The main reason is that the functionality is already embedded in the program so you can easily test your scripts from within the application.
Your code almost works once you take out aWord.Cut. Just be aware that certain things are treated as part of the Word collection that you might not expect. For instance, a comma with a space after it is treated as a "word". Same with a period. In the code below I tested for those two conditions but you may need more test depending on what your data looks like.
Lastly I needed to change your loop a bit because once you modify the collection, the iterator in the for each loop resets to what you modified. So in your example, every ninth word after the first would get changed.
i = 1
For Each aword In ActiveDocument.Words
If (aword <> ". " And aword <> ", ") Then
i = i + 1
aword.Select
If (i Mod 11) = 0 Then
blanks = ""
For Counter = 1 To Len(aword) - 1
blanks = blanks + "_"
Next Counter
blanks = blanks + " "
Word.Selection.TypeText (blanks)
End If
End If
Next aword
Related
My research shows that I need to use Visual Basic. I am a programmer/developer, but have never used VB so if anyone could dumb it down it would be appreciated.
Here's my working excel function:
=IF(MATCH(1,E1:DP1,0),D1,FALSE)
I want to loop a few of those numbers such that:
=IF(MATCH(141,E1:DP378,0),D378,FALSE)
THEN take my answers (which will be strings, because column D are all strings, the rest of the excel file are numbers)
=CONCAT
end goal: have 141 String arrays populated based on the data in my table.
I went ahead and made my first attempt at VBA like this:
Sub myFunc()
'Initialize Variables
Dim strings As Range, nums As Integer, answer() As Variant, listAnswers() As Variant
'set variables
strings = ("C1:C378")
nums = 141
i = 0
j = 0
ReDim Preserve answer(i)
ReDim Preserve listAnswers(j)
'answer() = {""}
'for each in nums
For counter = 0 To nums
ReDim Preserve listAnswers(0 To j)
'set each list of answers
listAnswers(i) = Join(answer(), "insertJSONcode")
j = j + 1
'for each in Stings
For Each cell In strings
If cell <> "" Then
ReDim Preserve answer(0 To i)
answer(i) = 'essentially this: (MATCH(2,E1:DP1,0),D1,FALSE)
i = i + 1
end If
next cell 'end embedded forEach
Next LCounter 'end for loop
'is this possible? or wrong syntax?
Range("A:A").Value = listAnswers() ' should print 141 arrays from A1 to A141
End Sub
EDIT:
Important note I do NOT need to call the sheet by Name. I've successfully written integer values to by excel sheet in column A without doing so.
Also, the VBA I wrote I was never intended to work, I know it's broken at least where answer(i) is supposed to write to something. I'm only putting that code there to show I was able to at least able to get into spitting distance of the proper logic and prove I've put some serious effort into solving the problem and give a rough starting point.
Here's an image of the excel format. Column C goes down to 378 and the numbers listed from E through DP are populated by a database. It consists of blank cells and numbers between 1 and 141.
Looking back at my if statement:
=IF(MATCH(2,E2:DP2,0),D2,FALSE)
If I were to type that exactly into cell B2 it would output the correct answer "text2". which is neat and all, but I need every instance of text 2 written out, then CONCAT those results. Easy so far, I could drag that down all the way through column B and have all of my "text" strings in one column, CONCAT that column and there's the answer. However I don't just need #2, I need each number between 1 and 141. Plus I want to avoid writing 141 columns with a CONCAT on top of each one.
I have a range (rng) which has the word "means" somewhere in it. I'm trying to determine if a word two words before "means" is underlined but can't quite figure out how.
Here's what my rng.Text is (note the brackets indicate the underlined text)
"[Automobile] - means a car that isn't a bus but can be an SUV"
Sometimes, it is "The way you have to go about it is with the various means of thinking".
The first one is a definition, since it has "means" preceeded by an underlined word. The second example is NOT a definition.
I'm trying to get my macro to look to 2 word before "means", but can't quite figure out how.
I am able to figure how many characters it is by this:
Dim meansLoc&
meansLoc = instr(rng.Text, "means")
Then, I can test If rng.Characters(meansLoc-9).Font.Underline = wdUnderlineSingle, but I run into problems if my defined word is only say 3 characters ("Dad - means a father", would error our since there means' index is 7, and 7-9 = -2). This is why I'd like to use words. (I can use one or two words before "means").
How can I return the character index of "means" in my rng. How do I get the "word index" (i.e. 2) from my rng?
Both Characters and Words are ranges, so one approach would be to compare the Start of the Character's range with each Word in the rng, e.g. you could start with
' assumes you have already declared and populated rng
Dim bDefinition As Boolean
Dim i as Integer
Dim meansLoc as Integer
Dim meansStart as Integer
meansLoc = instr(rng.Text,"means")
meansStart = rng.Characters(meansLoc).Start
bDefinition = False
For i = 1 To rng.Words.Count
If rng.Words(i).Start = meansStart Then ' i is your Word index (i.e. 3, not 2!)
If i > 2 Then
If rng.Words(i - 2).Font.Underline = wdUnderlineSingle Then
Debug.Print "Looks like a definition"
bDefinition = True
Exit For
End If
End If
End If
Next
If Not bDefinition Then
Debug.Print "Couldn't see a definition"
End If
Just bear in mind that what Word considers to be a "word" may be different from your normal understanding of what a "word" is.
I'm back with another question that probably has a simple answer. I really fall down when it comes to loops, so this is what I am trying to build.
I am building a form where user will type in a number between 1 and 156 (named range "GenNo") and click a Generate button.
I need a loop that will copy a template built in the "Template" tab of the spreadsheet with the named range also being "Template", and then insert it into the main form page the specified amount of times. This way the rest of the content and other named ranges should be pushed down accordingly.
Probably a very simple answer but I am terrible when it comes to loops and would not know where to start.
Thanks for your help.
EDIT: This attempt only generates one template in the form:
Sub Generate()
' Check if payslips are already generated
If Sheets("Data").Range("GenLogic").Value = 1 Then
MsgBox ("Already Generated! Please clear the form and regenerate.")
Else
Sheets("Data").Range("GenLogic").Value = 1
End If
' Loop code
Do Until Sheets("Data").Range("LoopLogic").Value = Range("GenNo").Value
Sheets("Template").Range("Template").Copy
Sheets("Overpayment Form").Range("Start").Insert
Range("LoopLogic") = Cell.Value + 1
Loop
End Sub
i would give this a shot; note that i removed your updating of your loop variables. Also, i've rewritten your loop to use a for, and shift down on insert.
Sub Generate()
' Check if payslips are already generated
If Sheets("Data").Range("GenLogic").Value = 1 Then
MsgBox ("Already Generated! Please clear the form and regenerate.")
Else
Sheets("Data").Range("GenLogic").Value = 1
End If
' Loop code
Dim iFrom As Long, iTo As Long, i As Long
iFrom = Sheets("Data").Range("LoopLogic").Value
iTo = Range("GenNo").Value
For i = iFrom To iTo
Sheets("Template").Range("Template").Copy
Sheets("Overpayment Form").Range("Start").Insert Shift:=xlDown
Next
End Sub
I am a complete novice in VBA and I'm in way over my head I think but the research necessitates it. I followed a great online tutorial series, which unfortunately didn't help me in solving 1 big problem: Data input.
My goal is to scrape patent data from google patents. To do so, it's pretty convenient that Google patents website is uniquely identified by the patent number. Thus what I want to achieve is the following:
Extract the patent number from a list in excel
Use that number to access the specific webpage
Extract application and publication year of patent, as well as patent number (as check)
Store all in a single excel sheet
Now, I can make 2,3, and 4 work but it's the loop that allows me to extract the patent numbers from excel and put them into my code that I am missing.
Here is the current code:
Private Sub CommandButton4_Click()
Dim obMF As Object
Dim patent As String
Dim grant_date As String
Dim app_date As String
Dim patent_number As String
patent_number = insert.Text ' insert.Text refers to a textbox in my interface
Call gotopat(patent_number, patent, app_date, grant_date)
found.Text = patent
grantdate.Text = grant_date
appdate.Text = app_date
output_row = 1 'Set the output row as 1 (this is where the title is)
Do
DoEvents
output_row = output_row + 1 'Increase output row with 1
Loop Until Sheets("bkcit").Range("B" & output_row) = ""
'Continue loop until that cell ~ Range is blank.
'Once a blank is found, we can put new data in there
'Store data into Worksheet "bkcit"
Sheets("bkcit").Range("B" & output_row) = patent
Sheets("bkcit").Range("C" & output_row) = grant_date
Sheets("bkcit").Range("D" & output_row) = app_date
In this code, found.Text, grantdate.Text, and appdate.Text are sourced from the scraping function which works perfectly. The important things about that function are:
Function gotopat(patent_number As String, patent As String, app_date As String, grant_date As String)
' A Bunch of other stuff
obMF.Navigate ("http://www.google.com/patents/US" & patent_number & "?")
'All the scraping code'
So, I want to replace the patent_number = insert.Text by a loop that looks in my excel sheet bkcit, column A and basically loops through all the unique patent numbers. I tried
input_row = 1
Do
DoEvents
input_row = input_row + 1
Range("C" & input_row) = patent_number
Loop Until Sheets("bkcit").Range("A" & input_row) = ""
But this seems to delete the first patent number in cell A2 and nothing more.
I'm thinking I'm pretty close to a working solution but your help would be fantastic, as always!
Thanks in advance
Simon
If I understand correctly, you have a column of patent numbers like this:
And you want to loop through each number and do something to it. Try this:
Sub loopPatents()
Dim patentNumber As Range
Dim patentRange As Range
Set patentRange = Worksheets(1).Range("A2:A10")
For Each patentNumber In patentRange
MsgBox ("Patent number: " & patentNumber)
'Do your stuff with the patent number here
Next patentNumber
End Sub
Alright, so I am editing a Macro for Reflection Workspace Terminal Emulator. I have a macro (it is long and not necessarily relevant, I can post the full code if anyone wants, it is about a page)
At the very end of the macro, a "Good Morning" Message is printed, and then also the value of a string variable named myName. This works fine.
What I want to do is then use a For loop to print a number of control characters (tab) equal to the amount printed in the Good Morning User. Here is the code I have so far:
Dim X As Integer
For i = 1 To i = (13 + Len(myName)) 'Good Morning + a space character will always = 13
ibmCurrentScreen.SendKeys (ControlKeyCode_Tab)
Next i
End Sub
I would use the Chr() function to print the control characters, but it seems that this particular program uses ControlKeyCode_X to print them.
The For...Next loop in VBA is a simple single variable counter based loop and cannot have complex criteria or multiple counters like in some other languages (e.g. in C# for(int i = 0, int j = 10; i < 10; i++, j--)). In VBA, therefore, the i = after To is redundant because it cannot be anything other than i.
The 'For' loop in VBA therefore only specifies the counter once. It should be:
For i = startVal To endVal [step incrementVal]
...
Next [i]
i = variable to vary
startVal = start value
endVal = end value (inclusive, i.e. To 10 will include 10 as the final value)
incrementVal = optional value to increment/decrement by each loop
(default = 1)
The counter is always incremented/decremented at the end of each loop then evaluated against endVal (i.e. for a vanilla increment by one loop, after exiting the loop it will be endValue + 1).
Note (unrelated to your situation) that you can change the value of i in the loop, e.g. to increment twice because of some special circumstance.
Specifying the variable with the Next statement is optional and has no effect on behaviour (any nested loop must always be closed before an outer loop) but is good practice for reference when you have many For...Next loops so it is clear which loop the Next is closing (although you should be religiously indenting or otherwise delineating your code)
So in your case For i = 1 To (13 + Len(myName)) instead.