|
|
Thread Tools | Display Modes |
#1
|
|||
|
|||
Detecting that previous character doesn't exist (i.e., present character is first in document)
How do I test whether a variable I've "set" actually exists before testing it in a conditional statement?
I have a loop that iterates through every character in a selection range and performs an operation depending on the content of the previous character (for example, if the previous character is an exclamation point). This works great so long as the selection doesn't include the first character of the document, at which point the macro fails and throws a '91' error. How do I test whether a variable I've set actually exists before testing it in a conditional statement, so that I can avoid this error? Code:
For Each strChar In Selection.Range.Characters Set strPrevChar = strChar.Previous(wdCharacter, 1) Set strNextChar = strChar.Next(wdCharacter, 1) If strPrevChar <> "!" Then ' Perform the operation End If Next strChar |
#2
|
||||
|
||||
You can either ignore the error and then test for
strPrevChar is Nothing or test if Selection.Range.Start > 0 Rather than testing every character that way, it is more efficient to ensure your range won't throw that error before the loop begins. Code:
Sub wtf() Dim rng As Range Set rng = Selection.Range If rng.Start = 0 Then rng.MoveStart Unit:=wdCharacter, Count:=1 If rng.End = ActiveDocument.Range.End Then rng.MoveEnd Unit:=wdCharacter, Count:=-1 For Each strChar In rng.Characters Set strPrevChar = strChar.Previous(wdCharacter, 1) Set strNextChar = strChar.Next(wdCharacter, 1) If strPrevChar <> "!" Then ' Perform the operation End If Next strChar End Sub
__________________
Andrew Lockton Chrysalis Design, Melbourne Australia |
#3
|
|||
|
|||
Thanks--
Follow-up question: why "declare" the rng variable rather than just always use Selection.Range? (1) It seems like extra code and (2) it actually seems to break the script. For example, if I do this, Code:
With Selection.Range.Find ' Get rid of any stricken-through text .ClearFormatting 'Is this needed? .Replacement.ClearFormatting 'Is this needed? .Text = "*" .MatchWildcards = True .Font.StrikeThrough = True .Replacement.Text = "" .Execute Replace:=wdReplaceAll End With With Selection.Range.Find ' Get rid of any underlining .Font.Underline = wdUnderlineSingle .Replacement.Font.Underline = wdUnderlineNone .MatchWildcards = False .Text = "" .Replacement.Text = "" .Execute Replace:=wdReplaceAll End With Code:
Dim rng As Range Set rng = Selection.Range With rng.Find ' Get rid of any stricken-through text .ClearFormatting 'Is this needed? .Replacement.ClearFormatting 'Is this needed? .Text = "*" .MatchWildcards = True .Font.StrikeThrough = True .Replacement.Text = "" .Execute Replace:=wdReplaceAll End With With rng.Find ' Get rid of any underlining .Font.Underline = wdUnderlineSingle .Replacement.Font.Underline = wdUnderlineNone .MatchWildcards = False .Text = "" .Replacement.Text = "" .Execute Replace:=wdReplaceAll End With |
#4
|
||||
|
||||
It was declared because that same range was needed 5 times and the code was completely different to your second question. Declaring a range makes it easier to follow the code and can reduce the number of contextual jumps required by the code. For instance
Selection.Range requires Word to first find out which document is active, then determine the start and finish positions of the selection in that document and then remember that range for the next command. Using a declared range reduces the 'thinking' required by the code. Working with ranges also reduces the ambiguity of where the 'selection' is located at any time. If your code happens to change the selection: either in the activedocument or because you have opened/activated a different document, the Selection.Range will give a very different result and is probably not what you were expecting. Now it just so happens that rng.Find is somewhat buggy and when something is found, the rng collapses to the found text. That is why your code doesn't 'find' anything underlined. In that case, you would need to redefine the range before doing the second find. In answer to your question in the code - I would think that the second find is actually searching for underlined AND strikethrough text since you didn't clear the formatting after the first time. That is the point of the .clearformatting which removes any of the sticky formatting that might already be retained from a previous finds performed by the user prior to your code running. You would need to .clearformatting again to remove the strikethrough condition in the second find before applying the font.underline condition otherwise you are searching for text with both.
__________________
Andrew Lockton Chrysalis Design, Melbourne Australia |
#5
|
|||
|
|||
Quote:
Quote:
Which is why I added those comments in the code. The clearformatting statements seem unnecessary. |
#6
|
||||
|
||||
I believe that the clearformatting is necessary although that doesn't appear to be the case in this instance. Before running the macro, use the regular find/replace dialog to find something formatted a particular way such as Bold or a style perhaps. If you close that dialog and then re-open it, you will see that it remembered this in your previous find. If you then run your macro without clearing those settings the macro has the potential to include those settings in its search. This is why it is good practice to clear this.
However, now that I am testing it, the code seems to ignore those settings which surprises me. In the case of your code, I would have said that you could remove the two lines in the middle End With With Selection.Range.Find since they are not strictly needed but if you do, the strikethrough is ALSO a factor in the second search. Since you are removing underlining, I would shorten the code and ensure you remove all types of underlining regardless of type. There is no need to search to remove underlining whilst retaining the text Code:
With Selection.Range.Find ' Get rid of any stricken-through text .ClearFormatting 'Is this needed? .Replacement.ClearFormatting 'Is this needed? .Text = "*" .MatchWildcards = True .Font.StrikeThrough = True .Replacement.Text = "" .Execute Replace:=wdReplaceAll End With Selection.Range.Font.Underline = wdUnderlineNone 'remove all underlining regardless of type
__________________
Andrew Lockton Chrysalis Design, Melbourne Australia |
#7
|
||||
|
||||
Come to that you could simply use
Code:
With Selection.Font .Underline = wdUnderlineNone .StrikeThrough = False End With Code:
With ActiveDocument.Range.Font .Underline = wdUnderlineNone .StrikeThrough = False End With Code:
Dim oRng As Range Set oRng = Selection.Range With oRng.Find .Font.StrikeThrough = True Do While .Execute If oRng.InRange(Selection.Range) Then oRng.Font.StrikeThrough = False oRng.Collapse 0 End If Loop End With Set oRng = Selection.Range 'Reset the range With oRng.Find .Font.Underline = wdUnderlineSingle Do While .Execute If oRng.InRange(Selection.Range) Then oRng.Font.Underline = wdUnderlineNone oRng.Collapse 0 End If Loop End With Code:
Dim oRng As Range Set oRng = ActiveDocument.Range With oRng.Find .Font.StrikeThrough = True Do While .Execute oRng.Font.StrikeThrough = False oRng.Collapse 0 Loop End With Set oRng = ActiveDocument.Range 'Reset the range With oRng.Find .Font.Underline = wdUnderlineSingle Do While .Execute oRng.Font.Underline = wdUnderlineNone oRng.Collapse 0 Loop End With
__________________
Graham Mayor - MS MVP (Word) (2002-2019) Visit my web site for more programming tips and ready made processes www.gmayor.com |
#8
|
||||
|
||||
Graham
The code was deleting strikethrough text and then removing single underlines (but retaining that underlined text). It appears the OP is not a fan of Words Revision Tracking so they are doing it manually. Your first code sample retains the strikethrough text so that is probably not what they wanted.
__________________
Andrew Lockton Chrysalis Design, Melbourne Australia |
#9
|
||||
|
||||
Yes indeed both of my codes sets only remove the strikethrough and not the text itself. It's an easy change to delete the text.
Code:
With oRng.Find .Font.StrikeThrough = True Do While .Execute oRng.Text = "" oRng.Collapse 0 Loop End With
__________________
Graham Mayor - MS MVP (Word) (2002-2019) Visit my web site for more programming tips and ready made processes www.gmayor.com |
#10
|
|||
|
|||
Haha, thanks, yes, that makes a lot more sense!
|
#11
|
|||
|
|||
Quote:
I've been developing a different VBA script that converts Word's revision tracking to legal-document revision format, but it's not perfect yet. I'm particularly having trouble with the part of the script that adds and deletes spaces, as appropriate, around double brackets where they have been inserted as part of the conversion process. Here's my crummy code that doesn't work, in case anyone's really interested. I think I was trying to write this before I understood fully what could be done with wildcard search & replace and I would probably do it differently now. Code:
For Each strChar In Selection.Range.Characters 'Add/delete spaces around double brackets Set strPrevPrevChar = strChar.Previous(wdCharacter, 2) 'I don't think this works MsgBox "Nothing selected or no revisions in selection.", vbOKOnly Set strPrevChar = strChar.Previous(wdCharacter, 1) Set strNextChar = strChar.Next(wdCharacter, 1) Set strNextNextChar = strChar.Next(wdCharacter, 2) 'I don't think this works If strChar.Text = "[" And strNextChar.Text = "[" Then 'Opening double bracket If strPrevChar.Text <> Chr(32) Then 'Insert leading space before opening double bracket strChar.InsertBefore (" ") Else 'Make sure there is only one leading space before opening double bracket Do While strPrevChar.Text = Chr(32) Loop End If Do While strNextNextChar.Text = Chr(32) 'Delete leading space after opening double bracket Loop ElseIf strChar.Text = "]" And strNextChar.Text = "]" Then 'Closing double bracket If strNextNextChar.Text <> Chr(32) Then 'Insert trailing space after closing double bracket End If End If Next strChar Thanks everybody for your help. Really fantastic answers here. |
#12
|
||||
|
||||
Unfortunately, with the wonder of hindsight, just about everybodies code could be improved once its been created. Looping through every character is horrendously slow and it appears you are probably doing this more than once so that magnifies it.
It might be worth taking a step back and looking at your requirements once again to see how to make the code really efficient. I would recommend getting away from Selections and strings in favour of ranges. For the job you describe here it would be WAY faster to do find/replaces instead of looping characters. eg with wildcards on find "([! ])\[\[" and replace with "\1 [[" to ensure there is always a space in front of any opening double square brackets
__________________
Andrew Lockton Chrysalis Design, Melbourne Australia |
#13
|
|||
|
|||
Quote:
EDIT: but it adds a space between deleted content and punctuation outside the deleted content, so I might end up with, for example, [[4]] , instead of [[4]], which is what is desired. Maybe a cheap fix would be to only add whitespace (where it doesn't exist) between underlined text and [[, or between ]] and underlined text? That way it would at least fix [[this]]sort of thing when [[this]] sort of thing is desired. Last edited by Robert K S; 07-20-2016 at 07:55 AM. |
#14
|
||||
|
||||
To avoid finding closing double braces followed by punctuation you could search for
"\]\]([a-zA-Z0-9])" Using Find to hit only braces followed by underlined text won't work because you can't specify which parts of the found string need the underline - its all or nothing.
__________________
Andrew Lockton Chrysalis Design, Melbourne Australia |
#15
|
|||
|
|||
Yeah, that's what I figured. Thanks for taking a look. You're the best.
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Macro to list all character styles in a document | ljd108 | Word VBA | 8 | 10-06-2022 01:56 PM |
Replace a random character with the same character | RickLegrand | Word | 7 | 07-23-2015 06:35 PM |
How can select from a specific character to another character | mohsen.amiri | Word | 2 | 02-19-2015 11:38 PM |
Regular (roman) character style doesn't change text to roman | kcbenson | Word | 2 | 10-16-2014 01:31 PM |
Finding or searching ^ character in word document | shahin3121 | Word | 2 | 03-05-2012 06:16 PM |