Log in

View Full Version : Solved: Special find and replace macro



bcn
11-09-2012, 08:05 AM
Hi,

I'm working on large documents (manuals) that have different styles applied to the names of GUI elements. So, for example, the "Import check box" would have a style called check box applied to the word "Import" and the "Installation dialog box" would have a style named dialog box to the word "Installation".

To make things worse, some of these styles are not consistently applied (some times there is a name in bold without the corresponding style applied). Now I want to replace all these names with a unique style called GUI element. In other words, replace all the x, y, and z styles with a style called GUI element.

Is it possible to write a macro that searches for any number of words (as the name can be made of 1, 2, 3, 4 or 5 words) in x style, replace them with the GUI style, then look for any munber of words in y stile and replace them with the GUI style, same with the z style, and then look for any number or words in bold followed by "dialog box" or by "check box" or by "tab", etc., and then have Word apply the GUI element style to them in an interactive way with the user (so that the user can click "Replace", "Find Next", etc.)? Or is it too complicated? Any hint will be highly appreciated!

Thanks,

Daniel

gmaxey
11-09-2012, 10:14 AM
Something like this (A, B, C) are existing character styles applied to text. D is the replacement style:
Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Dim strStyles() As String
Dim lngIndex As Long
Dim oRng As Word.Range
strStyles = Split("A|B|C", "|")
For lngIndex = 0 To UBound(strStyles)
Set oRng = ActiveDocument.Range
With oRng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Style = strStyles(lngIndex)
.Replacement.Style = "D"
.Execute Replace:=wdReplaceAll
End With
Next
End Sub

fumei
11-09-2012, 02:48 PM
Since the issue is the TEXT, why bother searching for the various possible character styles that may (or may not) be applied - as well as non-styles (manual bold formatting)?
Sub GUI_Element()
Dim strText() As String
Dim lngIndex As Long
Dim r As Word.Range
strText = Split("Import check box|Installation dialog box|Blah Blah element", "|")
For lngIndex = 0 To UBound(strText)
Set r = ActiveDocument.Range
With r.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = strText(lngIndex)
.Replacement.Font.Bold = False
.Replacement.Style = "GUI element"
.Execute Replace:=2
End With
Next
End SubThe replacement.font.bold = false is to take care of manual bold formatting.

bcn
11-10-2012, 04:32 AM
Hello Greg and Fumei,

Thank you very very much for this!!! You guys are great!

But I think I did not explain myself well. Let me show you a paragraph as way of example:

"The Import menu is unavailable because the content of the above mentioned dialog boxes depend on the selected role and service. Therefore, the role and service cannot be changed while the dialog box is open."

In this example, notice that the text mentions "menu" and "dialog box" and "dialog boxes". But the only GUI element with a name is the "Import menu". "Import" is the name, and "menu" is the label. "Import" is bold (with or without a style applied to it, but always bold) and is followed by a space and the word "menu" (or any other label, such as "dialog box", "tab", etc), In short, the "GUI element" style is meant for GUI names, not for their labels. Because they are not preceded by a name, "dialog boxes" and "dialog box" are just generic labels, thus they can be ignored.

Other examples:

Date box
Portrait option button
Import dialog box
Find and replace menu

(Here the style would be applied to the names "Date", "Portrait", etc., but not to the labels "box", "dialog box" etc..)

So, because these names are always in bold (with or without a specific style other than bold applied to them) and are always followed by a space and a label (" dialog box", " check box", " tab", etc.), I am guessing the only way to find and replace them is by telling VBA to search for a string of any number of words in bold followed by the string "[space]menu" or "[space]dialog box" or "[space]check box", etc., strip whatever style these words in bold have, and apply to them the "GUI element" style. Something like this:

Search for a string of words in bold and select it
If the string is followed by a space and the word "dialog box|tab|check box|etc."
then strip the selection from any style and apply the "GUI style" to the selection
else
search the next string

I hope I did not add more confusion,

Thanks a lot again!

Daniel

gmaxey
11-10-2012, 07:56 AM
bcn,

If order to straighten our a mess with VBA, it must be a logical mess. Try this:


Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Dim strStyles() As String
Dim lngIndex As Long
Dim oRng As Word.Range
Dim oRngTest As Word.Range
Dim strTest As String
strStyles = Split("x|y|z|Bold Text","|")
For lngIndex = 0 ToUBound(strStyles)
Set oRng =ActiveDocument.Range
With oRng.Find
.ClearFormatting
.Replacement.ClearFormatting
If lngIndex <UBound(strStyles) Then
.Style =strStyles(lngIndex)
.Replacement.Style = "GUI Element"
While .Execute
oRng.Select
IfMsgBox("Do you want to apply the GUI Element style to this text?", _
vbQuestion + vbYesNo, "Apply Style") = vbYes Then
oRng.Style= "GUI Element"
End If
Wend
Else
.Format = True
.Font.Bold =True
While .Execute
IfoRng.Style <> "GUI Element" Then
SetoRngTest = oRng.Duplicate
oRngTest.MoveEndWhile " ", wdForward
oRngTest.Collapse wdCollapseEnd
oRngTest.Expand wdWord
strTest =Trim(oRngTest)
SelectCase strTest
Case"menu", "dialog", "checkbox", "option"
oRng.Select
If MsgBox("Doyou want to apply the GUI Element style to this text?", _
vbQuestion + vbYesNo, "Apply Style") = vbYes Then
oRng.Style = "GUI Element"
End If
End Select
End If
Wend
End If
End With
Next
End Sub

bcn
11-10-2012, 08:57 AM
Hi Greg,

Such an amount of work! I feel ashamed! Thanks a lot. I really appreciate it!!!

I run your macro and get the following error message:

Run-time error: '5834':
Item with specified name does not exist.

for this line:

.Style = strStyles(lngIndex)

---------------------------------------------------

One question. Why do we have this line:

strStyles = Split("x|y|z|Bold Text", "|")

What if we don't look for any specific styles, just look for a string of words in bold, and tell the macro to strip these words from whatever style they have and apply the "GUI element" style as long as the selected words are followed by "dialog box" or "check box" or "tab" or "menu" and 4 or 5 other labels? PLease note that these labels are just plain text, they are not styles.

Thanks a lot!!!

Daniel

gmaxey
11-10-2012, 09:24 AM
We have that line because you explained in an earlier post that you wanted to look for styles named "x" "y" and "z." You can change "x" "y" and "z" to whatever style names you choose. I used "Bold Text" since I figured it doesn't exists just to get into the second phase of the procedure.

bcn
11-12-2012, 01:00 AM
Thank you very much, Greg. I know I wrote that in a previous post, but then fumei's comment made me think that, indeed, there was no need to search for those styles, because all they do is apply bold to the names. The document has these names in bold all over, some with styles and some just in bold manually applied by the author (by clicking the Home tab, and then clicking the B button in the Font group.)

What would I have to change in your code to only look for a group of words in bold followed by "[space]tab", "[space]dialog box", "[space]menu", etc., strip the words in bold from whatever style they have (if they have any) and apply them the "GUI element" style (which, by the way, also only applies bold to the names)?

Again... thanks a lot for your help and patience with me! Far from my intention to drive you crazy. :)

Daniel

gmaxey
11-12-2012, 06:14 AM
Daniel,

If you exchange x with "check box", y with "dialog", z with "menu" etc. does the code work for those instances?

The secondary reason I left those in is because there is no further processing involved. Notice in the second part of the code (finding bold) the additional processing involves quite a bit of range manipulation to determin the next word (single word e.g., dialog, checkbox, menu, option, etc.)

bcn
11-12-2012, 07:27 AM
Hi Greg,

Do you mean changing this line:

strStyles = Split("x|y|z|Bold Text", "|")

to this:


strStyles = Split("tag|dialog|menu|check box", "|") ?

When I do it this way, I get a "Run-time error 5834: Item with specified name does not exist" that points to this line:


.Style = strStyles(lngIndex)

Daniel

gmaxey
11-12-2012, 07:59 AM
When you step through the code line by line using the F8 key, is the error caused the first time the code hits that line?

If so, are you certain that you actually have a style named "tag" in the document?

fumei
11-12-2012, 04:15 PM
Seems to me there is confusion between text and style names.

bcn, do you actually have STYLES named:

strStyles = Split("tag|dialog|menu|check box", "|")

tag, dialog menu, check box??????

If you do (and I doubt it), then these are very bad names for styles.

bcn
11-13-2012, 02:57 AM
Hi Greg,

Yes, I have no styles with such names. I was trying to explain it in previous posts. Here is an example.

"Open the Import all the pictures dialog box"

In this sentence, "Import all the pictures", that is, the name of the dialog box, is in bold and may or may not have a style applied to it (other than Bold). The following words, "dialog box" (or "tab", or "check box", or "dialog box") are the labels or descriptors, and they do not have and should not have any style applied to them (other than "Normal"). But why are these descriptors or labels important? Because throughout the manual there are many words in bold, but I only want to apply the "GUI element" style created by me to the name of the GUI element, that is, to the words (or group of words) that are in bold (with or without a style other than "Normal" applied to them) and followed by a space and "dialog box", or "menu", or "tab", etc.

That's why I wrote in a previous post that the logic would be something like this:

Search for a string of words in bold and select it
If the string is followed by a space and the word "dialog box|tab|check box|etc."
then strip the selection from any style and apply the "GUI style" to the selection
else
search the next string

So in the case of this sentence:

"Open the Import all the pictures dialog box"

1. The VBA would look for "Import all the pictures" and select it
2 Then it would check if this string in bold is followed by a space and one of the descriptors ("dialog box", "tab", "check box", etc.)
3. If TRUE (if this condition is met), then it would apply the "GUI element" style to the selection (that is, to "Import all the pictures"), and look for the next string
4. If FALSE, it would look for the next string

The descriptor is only used to distinguish the bold strings (before the descriptor) that need to use the "GUI element" style from any other words in bold that are not names of GUI elements.

I hope I explained myself better this time. I think Fumei understood a part of it, when he said there is no need to look for strings with a certain style, just for strings in bold.

Kind regards,

Daniel

gmaxey
11-13-2012, 08:53 AM
The "need" to look for strings with a certain style was that the amout of code and processing is much less. You are the one that said that those styles were applied, not me.

Try:
Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Dim lngIndex As Long
Dim oRng As Word.Range
Dim oRngTest As Word.Range
Dim strTest As String

Set oRng = ActiveDocument.Range
With oRng.Find
.ClearFormatting
.Format = True
.Font.Bold = True
While .Execute
If oRng.Style <> "GUI Element" Then
Set oRngTest = oRng.Duplicate
oRngTest.MoveEndWhile " ", wdForward
oRngTest.Collapse wdCollapseEnd
oRngTest.Expand wdWord
strTest = Trim(oRngTest)
Select Case strTest
Case "menu", "box"
oRng.Select
If MsgBox("Doyou want to apply the GUI Element style to this text?", _
vbQuestion + vbYesNo, "Apply Style") = vbYes Then
oRng.Style = "GUI Element"
End If
Case "dialog", "option", "check"
oRngTest.MoveEnd wdWord, 1
strTest = Trim(oRngTest)
Select Case strTest
Case "dialog box", "option button", "check box"
oRng.Select
If MsgBox("Doyou want to apply the GUI Element style to this text?", _
vbQuestion + vbYesNo, "Apply Style") = vbYes Then
oRng.Style = "GUI Element"
End If
End Select
End Select
End If
Wend
End With
End Sub

bcn
11-13-2012, 09:25 AM
The "need" to look for strings with a certain style was that the amout of code and processing is much less. You are the one that said that those styles were applied, not me.

I know Greg, and I'm sorry for that. That was...mmm... let's say... useless information. It is true that some have different styles applied to them, but I did not realize in my first post that this information is not needed and even misleading to create the macro.

I'll test it right now and come back to you in a few minutes.

Thanks a lot again!

Daniel

bcn
11-13-2012, 09:37 AM
Greg,

Works great!

A couple of things:

Ths first one, very important. I just noticed it now.

1. If the code finds a string in bold that meets all the conditions AND the string already has the "GUI Element" style, it should leave it as is and look for the next one, without asking anything to the user. Is this what the code is doing?

2. In the Apply Style prompt, is it possible to add an info line saying what is the current style for the string in bold?

And last but not least,

3) What if I want to stop the macro before it reaches the end of the document? Is there a way to stop it manually?

Thanks a lot!

Daniel

gmaxey
11-13-2012, 10:22 AM
Daniel,

1. No. If the code finds a sting of bold text with "GUI Element" applied that text is not processed further. It applies the GUI Element style based on the condition you have defined. It does not verify that someone else may have applied that style incorrectly.

2. It is.

3. You could add code to provide an exit point or you can CTRL+Shift+Breakand click end.

All of your "add-ons" are things that are easily accomodated in the code that I have already handed you. There is an old saw "Give a man a fish and he eats for a day, Teach a man to fish and he eats for a lifetime." In the modern world that might should be changed to "Give a man a fish and he will eat for a day and expect you to feed him for the test of his life."

No insult intended, but it is time for you to at least look at the code I've given you and see if you can figure these other things out for yourself.

Hint: vbQuestion + vbYesNo can be change to vbQuestion + vbYesNoCancel and then code how to handled each one.

What you have created here is a classic demonstration of "scope creep." It is a nightmare for people who need to make a living doing this sort of thing. I call it the "x" analogy and discuss it in the attached.

Again, I've not meant to insult you and I'm not closing the door on you. I just want you show some effort. Fair enough?

bcn
11-14-2012, 08:25 AM
Fair enough, Greg!!!

I really appreciate all your help and your honesty. You are absolutely right and I apologize for my abusing of your precious time.

I'll see what I can figure out on my own.

All the best,

Daniel

gmaxey
11-14-2012, 09:01 AM
Daniel,

Post back what you work out. If you get stuck, show what you've tried and I'll be happy to help you out.

bcn
11-15-2012, 07:27 AM
Hi Greg,

Thanks for the kind offer. But before I try to understand the complex code you made for me, I want to try to understand this smaller one (also from you, I just added the first line):


Sub OpenClose()
'
'
Selection.Style = ActiveDocument.Styles("Button")
Dim oRng As Word.Range
Set oRng = Selection.Range.Duplicate
oRng.Collapse wdCollapseStart
oRng.InsertSymbol CharacterNumber:=-3971, Font:="Wingdings 3", Unicode:=True
Set oRng = Selection.Range.Duplicate
oRng.Collapse wdCollapseEnd
oRng.InsertSymbol CharacterNumber:=-3972, Font:="Wingdings 3", Unicode:=True
End Sub



This one I understand well and it is working fine. But then I copied it to make this other one:


Sub Quotes()
'
'
Selection.Style = ActiveDocument.Styles("GUI quoted")
Dim oRng As Word.Range
Set oRng = Selection.Range.Duplicate
oRng.Collapse wdCollapseStart
Selection.InsertSymbol CharacterNumber:=8220, Unicode:=True, Bias:=0
Set oRng = Selection.Range.Duplicate
oRng.Collapse wdCollapseEnd
Selection.InsertSymbol CharacterNumber:=8221, Unicode:=True, Bias:=0
End Sub



This second one is telling the program to apply a style called "GUI quotes" to the selection, and then add an opening quotation mark at the beginning of the selection and a closing quotation mark at the end.

The result? It adds the two characters and deletes the selection. So you end up with two quotation marks and no text in between. I was trying to find the culprit (maybe opening and closing quotation marks are treated differently for some reason?), but to no avail. Do you know why it is behaving like this?

Thanks a lot,

Daniel

gmaxey
11-15-2012, 07:42 AM
Daniel,
Look closely at the two code snippets that you posted. You will see that the first employs the .InsertSymbol method using the range object which is first collapsed at the start of the selection then collapsed at the end of the selection. Is that the case in the snippet of code?

bcn
11-15-2012, 12:01 PM
Greg,

I just sent you a private message on your website.

Feel free to write back to the address I give there.

Thanks,

Daniel