PDA

View Full Version : Coloring Words to imitate VBA color coding



malik641
10-09-2007, 12:00 PM
Hey all,

I'm not really familiar with Word VBA....at all. I'm looking for a code snippet to color-code the selected text to imitate VBA's color coding in the VBE. I will basically copy and paste my code into a word document, highlight that code, and run the macro to color code it (green for comments, blue for keywords, maybe Red for string literals).

Can this be done? (I assume so).

I realize it would be difficult to distinguish ALL the keywords VBA has, so I will implement all the keywords myself. I just need an example and I will finish/polish the code myself. Also, if anyone has trouble with distinguishing string literals and comments, I'll try to create an algorithm for it.

Any help is well appreciated :)

Thanks!

Oh yeah, and don't worry about Line continuation characters "_" when it comes to comments. I think this would be a bit difficult to accomplish.

lucas
10-09-2007, 12:15 PM
There are editors out there Joseph...
http://www.ultraedit.com/

Bound to be some free ones.....

or is this an exercise?

malik641
10-09-2007, 12:51 PM
Good idea, Steve. I just thought someone would have already made something in VBA for this...ah well.

By the way, there is a Free editor. Visual Basic 2005 Express :)
Copy and paste VBA code into a module/class (VB 2005). Then cut that code and paste into Word = Beautiful :cloud9:

All is well now.

lucas
10-09-2007, 12:56 PM
Another consideration Joseph. I don't think Word is pure text....it is formatted and might cause some problems...

malik641
10-09-2007, 12:59 PM
I'm not sure I understand. I only copy the code from VBE to VB 2005 window, then cut that text and paste it into Word. After that, I have no use of the code that is in the Word document (since I still have it in a .bas file anyway).

lucas
10-09-2007, 01:09 PM
Just a thought....I may be off base on this.

fumei
10-09-2007, 01:13 PM
Hi Joseph. This comes up periodically and I have never seen a good enough solution that I would actually use. So-so solutions, half-a$$ed solutions, sure....seen those.

UltraEdit is a great editor.

The problem is actually with how difficult and convoluted the logic has to be.Sub FeebleAttempt()
Dim aWord
Dim var
Dim MyKeywords()
MyKeywords = Array("On", "Error", "Resume", "Next", _
"Function", "String", "Object", _
"If", "End", "Then", "Sub", _
"Const", "Dim", "Set", "Declare", _
"Object", "Is", "Not", "Nothing", "As")

For Each aWord In Selection.Range.Words
For var = 0 To UBound(MyKeywords)
If Trim(aWord) = MyKeywords(var) Then
aWord.Font.Color = wdColorRed
End If
Next
Next
End SubOK, fine. The array would have to be expanded of course. This does work, for the words in the array.

EXCEPT, you want comments...and who doesn't. Which means you (probably) do NOT want the words to be red IF they are in a comment:

' On Error re-route to blah routine

In the above keyword procedure, On Error are, in fact, words in the keyword array. You could get around this by making sure you NEVER use capitalized words in your comments, and you DO use capitalized words in the array. Presumably you are not copying and pasting until the VBA parser has done its thing and capped keywords.

Further, you COULD do a check for paragraphs first, checking for the comma of a comment...but you had better also check for the double slashes as well.

And on and on and on. Checking for string literals yadda yadda yadda. I have made my own half-a$$ed attempts to automate the process but have never been satisfied and no longer bother.

I used to use character styles to (sort of) duplicate the effect.

The people I write documentation for are techies, and, frankly, should be able to read code. As text. My documentation does include code, but all I do now is have a slightly bigger font and bold for the start and end of procedures. Oh, and I do use a different style for comments. I always use a comma, so it is easy to loop through paragraphs and if it starts with a comma then it is MyComments style. Other than that....screw 'em...they can read.

Proper indenting though...that is crucial.

fumei
10-09-2007, 01:17 PM
Missed those last posts. Yes, for sure, if you want to bring through Visual Studio.

"After that, I have no use of the code that is in the Word document (since I still have it in a .bas file anyway)."

Not quite following that. Do you mean the code that you pasted into the Word document? Or the code that was in the VBE. I assume you mean the code that was in the VBE. In which case...ummmm, why do you want it in the Word document? Do you save all your VBA code as .bas files?

malik641
10-09-2007, 01:41 PM
Hi Joseph. This comes up periodically and I have never seen a good enough solution that I would actually use. So-so solutions, half-a$$ed solutions, sure....seen those.

UltraEdit is a great editor.

The problem is actually with how difficult and convoluted the logic has to be.Sub FeebleAttempt()
Dim aWord
Dim var
Dim MyKeywords()
MyKeywords = Array("On", "Error", "Resume", "Next", _
"Function", "String", "Object", _
"If", "End", "Then", "Sub", _
"Const", "Dim", "Set", "Declare", _
"Object", "Is", "Not", "Nothing", "As")

For Each aWord In Selection.Range.Words
For var = 0 To UBound(MyKeywords)
If Trim(aWord) = MyKeywords(var) Then
aWord.Font.Color = wdColorRed
End If
Next
Next
End SubOK, fine. The array would have to be expanded of course. This does work, for the words in the array.

EXCEPT, you want comments...and who doesn't. Which means you (probably) do NOT want the words to be red IF they are in a comment:

' On Error re-route to blah routine

In the above keyword procedure, On Error are, in fact, words in the keyword array. You could get around this by making sure you NEVER use capitalized words in your comments, and you DO use capitalized words in the array. Presumably you are not copying and pasting until the VBA parser has done its thing and capped keywords.
Hey Gerry,
Very good points. And thanks for that sample code.

I completely agree that the algorithm for the comments would not be an easy task. "How do you distinguish apostrophes in strings (between quotation marks) versus a comment?" Comes to mind as a difficult task to achieve with these comments. Not to mention continuation markers.

Just for fun (and to get some Word VBA practice) I'll give this task a shot on my own...just to see what I can come up with. I'll post back with the code and you guys can feel free to critique. Maybe something will come out of this.


Further, you COULD do a check for paragraphs first, checking for the comma of a comment...but you had better also check for the double slashes as well.
But double slashes are comments for C/C++/C#, no? I was looking for only VB(A) to start off with (and I'm not completely familiar with the coloring of C/C++/C#'s code).


I used to use character styles to (sort of) duplicate the effect. Never heard of character styles. I'll look that up later.



The people I write documentation for are techies, and, frankly, should be able to read code. As text. My documentation does include code, but all I do now is have a slightly bigger font and bold for the start and end of procedures. Oh, and I do use a different style for comments. I always use a comma, so it is easy to loop through paragraphs and if it starts with a comma then it is MyComments style. Other than that....screw 'em...they can read.

Proper indenting though...that is crucial. This is for my boss and I would like to have it color-coded for easy reading. I don't work for a programming company, so I'm not expecting him to be able to interpret it, but he'll be able to follow with the color-coding for sure (he does have some programming experience).

Proper indenting is done by me in the VBE when I write the code. When I copy and paste it into Word, it still has the same indentings as the VBE. That won't be an issue for me.



Missed those last posts. Yes, for sure, if you want to bring through Visual Studio.

"After that, I have no use of the code that is in the Word document (since I still have it in a .bas file anyway)."

Not quite following that. Do you mean the code that you pasted into the Word document? Or the code that was in the VBE. I assume you mean the code that was in the VBE. In which case...ummmm, why do you want it in the Word document? Do you save all your VBA code as .bas files? What I mean is, I use my code all the time (in my Excel files, Access, etc). All I'm doing here is copying that code and pasting into a Word document. The code in the Word document is only meant for the Word document. The original code is not altered by this process. This is merely a means to display the work I've done in the form of a Word document.

I save almost all my .bas files periodically. I store them away incase I can use it again in another project (even if I have to modify it a little, it still saves me time). And, of course, I create back-up copies of my Excel/Word/Access files periodically.

fumei
10-09-2007, 02:44 PM
Smart.

If you do play with versions of FeebleAttempt, remember to Trim aWord. The variable aWord includes any trailing space.

In other words, with that array:

Function Yadda(strIn As String) As String

"Function" would NOT be colored.
The two "String" would be. Assuming the second String terminates with a paragraph mark!

The array has "Function", aWord would be "Function ".

fumei
10-09-2007, 03:21 PM
Just as a further note to the logic.

Yadda As String
Blah As Document
DippityDoDah As Application

Other than actually listing each and every possible thing that could be an "As" - the array route - you could run through the text logically. Check for "As ", and then color the NEXT word.

Something like:Dim aWord
Dim NextWord
For Each aWord In Selection.Range.Words
If aWord = "As " Then ' notice the space added
Set NextWord = aWord.Next
' you MUST do this
NextWord.Expand unit:=wdWord
NextWord.Font.Color = wdColorRed
End If
NextIt is important to realize what Word thinks of as a "word".

"How many words in this sentence?"

There are EIGHT "words" in the sentence above.

How
many
words
in
this
sentence
?
paragraph mark

Yes, aWord will determine the question mark as a separate and individual "word"...as well as the paragraph mark...as a "word".

BEWARE! Try it. Type in the sentence and an Enter to terminate it. Select it and run:Dim j As Long
Dim aWord
For Each aWord In Selection.Range.Words
msg = msg & aWord & vbCrLf
j = j + 1
Next
MsgBox msg & vbCrLf & "for a total of " & j & " words."It will display:

How
many
words
in
this
sentence
?

for a total of 8 words.

with the paragraph mark being....invisible.

Notice I bolded "Words". It is sort of a Collection, but...not really.

Say you have:

Set SA = CreateObject("Shell.Application")

How many "words"???? There are 10:

Set
SA
=
CreateObject
("
Shell
.
Application
")
the invisible paragraph mark

Notice that dots (.) are counted as "words". This has profound consequences - hahahahahahaha - when using this for text based on the object.method, object.property etc. syntax.

Are we having fun yet?

malik641
10-09-2007, 03:59 PM
Excellent info. It is very appreciated :friends:

I had an idea of how we could possibly accomplish this. (By the way, I really like the "As " idea. That was a nice trick)

Color the text in three different stages:
1. Keywords first
2. String Literals second
3. Comments last

This way, if a keyword gets colored and it's part of a literal text, or a comment, it doesn't matter because it will be colored correctly in the end.

So how do you implement each?

1. Keywords: Use your FeebleAttempt :) (like the pun?...is that considered a pun?)

2. String Literals:
Possibly the same way as the Keywords method (it looks doable from what you showed me...but looks can be deceiving)

3. Comments:
I'm thinking maybe you could break down the Range into an array by splitting the Range by vbCr (I read that it wouldn't work to split with vbLf or vbCrLf). Then use regular expressions to determine if the lines need comments in it.

Then maybe you can use the match number (of regex) to determine the starting and ending character numbers of the Range() to highlight.

Just a thought, for now. Glad I have it written down, though. I have class in 2 minutes!!! :)



Are we having fun yet? I guess you haven't read my thread on "Office phrases that annoy me" :giggle

...or maybe you HAVE!! :)

lucas
10-09-2007, 04:21 PM
Yes Gerry, he is having fun. This is right down his alley.

Is indenting going to be an issue with this?

malik641
10-09-2007, 06:11 PM
Yes, Steve is absolutely correct. I'm having a lot of fun with this :)

I think indenting may be an issue if a Tab is counted as 1 character to VBA, and X spaces to Word....But I'll check that.

fumei
10-09-2007, 11:02 PM
The weirdest part of this is...there is NO "word" object in Word.

There are Sentence objects.
There are Paragraph objects.

But there is no Word object. Even though there is a Words "collection" - as in Range.Words - it is really not a collection, IMO. They are ranges set with delimiters.

How many words in this sentence?

Selecting that:

If you use Tools > Word Count, you get 6.
If you use Selection.Range.Words.Count, you get 8.

Go figure.

? is a word to the Words "collection". In fact, it is actually more like a Method. The "words" are calculated, derived, from the range.

You can not declare something like

Dim aWord As Word

No such beastie.

As for Tabs. I hate to tell you this, but...ahem...they are brought into Word as spaces. The count equals the Tab Width set in Tools > Options in the VBE.

If you have two tabs, and the Tab Width is 4, it comes into Word as 8 spaces.

vbTab is ONE character in text, but the VBE does not, in fact, use vbTab...for Tabs. It uses spaces.

Even if you use SmartIndent (which I do), they still cross over as spaces in text.

Let's take:
Case "what"
MsgBox "who"


Now in the VBE, it is:

<tab><tab>Case "what"
<tab><tab><tab>Msgbox "who"

[Actually, of course you would be using the Enter after the "what" and ONE tab...but for our purposes of discussion....]

the "word" count of Msgbox "who" = 6

space
Msgbox
"
who
"
paragraph mark

In our puny non-Microsoft minds, it looks like two words (one being a string literal)...but it is not.

Further, there are actually 12 spaces (characters) leading to Msgbox, (from the three Tabs in the VBE) although only one "word". The 12 characters is considered one "word".

1. Keywords: Use your FeebleAttempt (like the pun?...is that considered a pun?)

2. String Literals:
Possibly the same way as the Keywords method (it looks doable from what you showed me...but looks can be deceiving)

3. Comments:OK. Keywords...yeah, you can do it. You could expand the "As " logic like this:Dim aWord
Dim NextWord
Dim PrevWord
For Each aWord In Selection.Range.Words
If aWord = "As " Then
Set NextWord = aWord.Next
NextWord.Expand unit:=wdWord

Set PrevWord = aWord.Previous
PrevWord.Expand Unit:=wdWord

NextWord.Font.Color = wdColorRed
PrevWord.Font.Color = wdColorRed
End If
Next So:

Dim ThisDoc As Document

would make both ThisDoc and Document red. The logic flows from the "As " both ways, the Next word, and the Previous word.

That would take care of "As " keywords.

Dim, Public could have similar logic worked out, but that was my initial point. How much effort and work is this worth????? Because you would HAVE to work out the difference between

Dim aWord (no As or object)...and
Dim aWord As Word.Application

Unless you consistently NEVER declared variables without a qualifier.

Dim aWord As Variant

2. String literals. This is far more tricky that it would seem. Can it be done? Probably, but again, how much is it worth? The biggest problem of course is double quote marks.

3. Comments. Actually, I think this is by far the easiest. I have comments as separate lines. I rarely have them on a code line.

I do this:
' this is a comment

but rarely this:
Select Case "whatever" ' yadda

IF, and only IF, you do use comments as their own lines, then it is a simple matter to run through the paragraphs.Dim oPara As Paragraph
For Each oPara In Selection.Paragraphs
Select Case Asc(oPara.Range.Text)
Case 32
' a space, or 12 spaces (ie.Tabs in the VBE)
' and if the SECOND word is a comma
If Asc(oPara.Range.Words(2)) = 39 Then
oPara.Range.Font.Color = _
wdColorBrightGreen
' a comment
End If
Case 39
' a comma
oPara.Range.Font.Color = _
wdColorBrightGreen
End Select
Nextwould make:

' start a comment here
Select case strWhatever

Case "what"
' this is a comment
MsgBox "who"
If this = that
' this is a comment
End If
Case vbTab

all comments BrightGreen. Regardless of the number of Tabs used in the VBE. The "word" count will only count one of them, therefore if Words(1) = Chr(32) a space, AND Words(2) = Chr(39) a comma...then it is a comment line.

If Words(1) is a comma...then it is comment line.

This would work if you are consistent in your use of comments. If they are tacked on the end of code lines, then obviously the above will NOT work. If you are consistent, using their own lines, then there is no need to get into calculating ranges and starts, and end and yadda yadda yadda. Could it done? Probably. More work than I am interested in.

TonyJollans
10-10-2007, 12:09 AM
This could, I suppose, be a good learning exercise except that it would be a lot of work with probably little to show for it at the end. As Gerry says ... more work than I am interested in.

Slight correction to Gerry's otherwise fine post ....

There is, of course, a Word object - it is just that it is Word and not A word. Also there is not a Sentence object.

malik641
10-10-2007, 05:33 AM
Again, very interesting and intriguing info.

I will have a deeper look at your code, Gerry. Thanks for the 'comments' code.


As for Tabs. I hate to tell you this, but...ahem...they are brought into Word as spaces. The count equals the Tab Width set in Tools > Options in the VBE.

If you have two tabs, and the Tab Width is 4, it comes into Word as 8 spaces.

vbTab is ONE character in text, but the VBE does not, in fact, use vbTab...for Tabs. It uses spaces. Well, thankfully RegEx counts Tabs as spaces as well :)



OK. Keywords...yeah, you can do it. You could expand the "As " logic like this:Dim aWord
Dim NextWord
Dim PrevWord
For Each aWord In Selection.Range.Words
If aWord = "As " Then
Set NextWord = aWord.Next
NextWord.Expand unit:=wdWord

Set PrevWord = aWord.Previous
PrevWord.Expand Unit:=wdWord

NextWord.Font.Color = wdColorRed
PrevWord.Font.Color = wdColorRed
End If
Next Well, in VBA object variables are 'usually' not colored anyway (unless the Identifiers color is set in Tools-->Options). So I don't think I'll be needing this. That does seem like a lot of work there.


2. String literals. This is far more tricky that it would seem. Can it be done? Probably, but again, how much is it worth? The biggest problem of course is double quote marks.
I don't know, there. I think I've got this part nailed :) Check out the code at the end.



3. Comments. Actually, I think this is by far the easiest. I have comments as separate lines. I rarely have them on a code line.

I do this:
' this is a comment

but rarely this:
Select Case "whatever" ' yadda

IF, and only IF, you do use comments as their own lines, then it is a simple matter to run through the paragraphs.Dim oPara As Paragraph
For Each oPara In Selection.Paragraphs
Select Case Asc(oPara.Range.Text)
Case 32
' a space, or 12 spaces (ie.Tabs in the VBE)
' and if the SECOND word is a comma
If Asc(oPara.Range.Words(2)) = 39 Then
oPara.Range.Font.Color = _
wdColorBrightGreen
' a comment
End If
Case 39
' a comma
oPara.Range.Font.Color = _
wdColorBrightGreen
End Select
Nextwould make:

' start a comment here
Select case strWhatever

Case "what"
' this is a comment
MsgBox "who"
If this = that
' this is a comment
End If
Case vbTab
all comments BrightGreen. Regardless of the number of Tabs used in the VBE. The "word" count will only count one of them, therefore if Words(1) = Chr(32) a space, AND Words(2) = Chr(39) a comma...then it is a comment line. Thanks for the code, Gerry. I will have a go at it. I may just use RegEx to cover all sorts of comments, but I have not reached that point yet.


More work than I am interested in.
As Gerry says ... more work than I am interested in. I don't know guys, I think I've got the Keywords and String Literals pretty well without too much code:

Sub FeebleAttempt()
Dim aWord, NextWord, var, aLine, MyKeywords()

Dim sText As String
Dim sLines() As String
Dim sWords() As String
Dim strPattern As String, strMatches() As String
Dim i As Long, j As Long, lngCharacterCount As Long

MyKeywords = Array("On", "Error", "Resume", "Next", _
"Function", "String", "Object", _
"If", "End", "Then", "Sub", _
"Const", "Dim", "Set", "Declare", _
"Object", "Is", "Not", "Nothing", "As", "Public", "Private", _
"For", "Each", "In", "To", "Option", "Optional", "Explicit")

' First reset all colors in selection range
Selection.Font.Color = wdColorBlack

' ^^^^^^^^^^^KeyWords^^^^^^^^^^^^^^^^^^^^^^^^^^^^
' This will color keywords Blue
For Each aWord In Selection.Range.Words
For var = 0 To UBound(MyKeywords)
' Check for As keyword to highlight next variable (next word)
If aWord = "As " Then
Set NextWord = aWord.Next
NextWord.Expand unit:=wdWord
NextWord.Font.Color = wdColorBlue
End If

If Trim(aWord) = MyKeywords(var) Then
aWord.Font.Color = wdColorBlue
End If
Next
Next
' ^^^^^^^^^^^KeyWords^^^^^^^^^^^^^^^^^^^^^^^^^^^^

' ###########String Literals####################################
' First find all occurences of quotation marks (") and color
' them red.
With Selection.Range.Find
.ClearFormatting
.Text = """"
.Replacement.Font.Color = wdColorRed
.Execute Replace:=wdReplaceAll
End With

strPattern = "(""|?|?)"

Call regexMatch(Selection.Range.Text, strPattern, True, True, strMatches())

For i = 0 To UBound(strMatches, 2) Step 2
On Error GoTo OverHere
' Debug.Print strMatches(0, i)
' Debug.Print strMatches(1, i)
' Debug.Print strMatches(2, i)

ActiveDocument.Range(Start:=(Selection.Range.Start) + strMatches(0, i) + strMatches(1, i), _
End:=(Selection.Range.Start) + strMatches(0, i + 1)).Font.Color = wdColorRed

Debug.Print ActiveDocument.Range(Start:=(Selection.Range.Start) + strMatches(0, i) + strMatches(1, i), _
End:=(Selection.Range.Start) + strMatches(0, i + 1)).Text
OverHere:
Next
On Error GoTo 0

' ###########String Literals####################################

' ------------------Comments------------------------------------
' Lines starting with a comment mark
' ******************************************

' ******************************************

' Lines that contain comments at the end

' ------------------Comments------------------------------------


End Sub

Public Sub regexMatch(ByRef strStringToTest As String, _
ByRef strPattern As String, _
ByVal blnMultiline As Boolean, _
ByVal blnGlobal As Boolean, _
ByRef strMatches() As String)
' *************************************************************************** *
' Author:
' Date:
' Purpose: Return indices of matches for a regEx pattern on a string passed
' Pre-Conditions:
' Post-Conditions:
' References: Microsoft VBScript Regular Expressions 5.x
' *************************************************************************** *

Dim regex As VBScript_RegExp_55.RegExp
Dim regexMatchCollection As VBScript_RegExp_55.MatchCollection
Dim regexMatch As VBScript_RegExp_55.Match
Dim i As Long

Set regex = New VBScript_RegExp_55.RegExp
' Set regex parameters
With regex
' Look for global matches
.Global = blnGlobal
' Set Multiline
.MultiLine = blnMultiline
' Set pattern
.Pattern = strPattern

' Test if patten finds a match
If (.Test(strStringToTest) = False) Then Exit Sub

' Retrieve pattern collection
Set regexMatchCollection = .Execute(strStringToTest)
End With

' Loop through matches and resize array
i = 0
For Each regexMatch In regexMatchCollection
ReDim Preserve strMatches(2, i)
strMatches(0, i) = regexMatch.FirstIndex
strMatches(1, i) = regexMatch.Length
strMatches(2, i) = regexMatch.Value
i = i + 1
Next
End Sub

:)

malik641
10-10-2007, 01:29 PM
:) Please let me know what you guys think. It doesn't handle line continuations on comments, though. I might try to tackle that next.

I decided to switch my method for the string literals to use the same method as my comment coloring. It basically uses a regular expression to capture quotation marks, apostrophes, and vbCr (I'm pretty sure vbCr is the only one necessary for Word). Then it takes the match indices and loops through them. The basic idea is that for a comment to be considered a comment , it cannot be surrounded by quotes (part of a string literal). This also catches lines that start with comments. Once this condition is met, everything from that point on to the vbCr is highlighted green. For string literals, the loop will find when a quotation mark is the current value, then it will loop until it finds the next quotation mark and colors everything between the two (including the quotation marks). Since VBA won't allow a single quotation mark in code, this will be fine (except for comments, but the code handles comments already).

It's a little confusing, but the end result looks good (to me). The one thing I'm worried about is how large of a string can the RegEx object handle? (I tested around 15,000 characters, and it was fine...but still)

Anyway have a look and let me know what you guys think:
Option Explicit

' Use Regular Expressions

' KEYWORDS FIRST
' LITERAL STRINGS NEXT
' COMMENTS LAST

Sub MyAttempt()
Dim aWord, NextWord, var, aLine, MyKeywords()

Dim sText As String
Dim sLines() As String
Dim sWords() As String
Dim i As Long, j As Long, k As Long
Dim strPattern As String
Dim strMatches() As String

MyKeywords = Array("On", "Error", "Resume", "Next", _
"Function", "String", "Object", _
"If", "End", "Then", "Sub", _
"Const", "Dim", "Set", "Declare", _
"Object", "Is", "Not", "Nothing", "As", "Public", "Private", _
"Option", "Optional", "Explicit", "For", "Each", "True", "False")

' First reset all colors in selection range
Selection.Font.Color = wdColorBlack

' ^^^^^^^^^^^KeyWords^^^^^^^^^^^^^^^^^^^^^^^^^^^^
' This will color keywords Blue
For Each aWord In Selection.Range.Words
For var = 0 To UBound(MyKeywords)
' Check for As keyword to highlight next variable (next word)
If aWord = "As " Then
Set NextWord = aWord.Next
NextWord.Expand unit:=wdWord
NextWord.Font.Color = wdColorBlue
End If

If Trim(aWord) = MyKeywords(var) Then
aWord.Font.Color = wdColorBlue
End If
Next
Next
' ^^^^^^^^^^^KeyWords^^^^^^^^^^^^^^^^^^^^^^^^^^^^


' ------------------String Literals & Comments------------------------------------
' ONLY WORKS WHEN AT LEAST ENTIRE LINE IS SELECTED. NOT FROM MIDDLE OF LINE ONWARD
ReDim strMatches(2, 0)
' Pattern to match an apostraphe and quotation mark and carriage return
' \r = Carriage Return character
' \n = New line character
strPattern = "(""|')|(\r|\n)"

Call regexMatch(Selection.Range.Text, strPattern, True, True, strMatches())

' Loop through finding an apostraphe NOT enclosed by quotes
i = 0
j = 0
k = UBound(strMatches, 2)

Do
Debug.Print strMatches(0, i) ' Index (character position)
Debug.Print strMatches(1, i) ' Length
Debug.Print strMatches(2, i) ' Value

If strMatches(2, i + 1) = vbCr Then Debug.Print "YES"

Select Case strMatches(2, i)
Case "'"
' Whole/(Rest of) line is a comment. Search for carriage return
' Loop until carriage return, then change i
j = i
Do Until j = k
j = j + 1
If strMatches(2, j) = vbCr Then
' Color comments
ActiveDocument.Range(Start:=(Selection.Range.Start) + strMatches(0, i), _
End:=(Selection.Range.Start) + strMatches(0, j)).Font.Color = wdColorGreen

If j = k Then
' End of selection
i = k
Else
' Next line/paragraph
i = j + 1
End If

Exit Do
End If
Loop

' Search for Quotes ignoring apostrophes between them
Case """"
' Search for next quotation mark or vbCr
j = i
Do Until j = k
j = j + 1
If strMatches(2, j) = """" Then
' Color quotes
ActiveDocument.Range(Start:=(Selection.Range.Start) + strMatches(0, i), _
End:=(Selection.Range.Start) + strMatches(0, j) + 1).Font.Color = wdColorRed
' Exit do, change i
If j = k Then
' End of selection
i = k
Else
' Next line/paragraph
i = j + 1
End If

Exit Do
ElseIf strMatches(2, j) = vbCr Then
If i = k Then i = k Else i = j + 1
End If
Loop

Case vbCr
' Set i to next match
If i < k Then i = i + 1

End Select

'ActiveDocument.Range(Start:=(Selection.Range.Start) + strMatches(0, i) + strMatches(1, i), _
End:=(Selection.Range.Start) + strMatches(0, i + 1)).Font.Color = wdColorRed
Loop Until i = k

' ------------------String Literals & Comments------------------------------------


End Sub

Public Sub regexMatch(ByRef strStringToTest As String, _
ByRef strPattern As String, _
ByVal blnMultiline As Boolean, _
ByVal blnGlobal As Boolean, _
ByRef strMatches() As String)
' *************************************************************************** *
' Author:
' Date:
' Purpose: Return indices of matches for a regEx pattern on a string passed
' Pre-Conditions:
' Post-Conditions:
' References: Microsoft VBScript Regular Expressions 5.x
' *************************************************************************** *

Dim regex As VBScript_RegExp_55.RegExp
Dim regexMatchCollection As VBScript_RegExp_55.MatchCollection
Dim regexMatch As VBScript_RegExp_55.Match
Dim i As Long

Set regex = New VBScript_RegExp_55.RegExp
' Set regex parameters
With regex
' Look for global matches
.Global = blnGlobal
' Set Multiline
.MultiLine = blnMultiline
' Set pattern
.Pattern = strPattern

' Test if patten finds a match
If (.Test(strStringToTest) = False) Then Exit Sub

' Retrieve pattern collection
Set regexMatchCollection = .Execute(strStringToTest)
End With

' Loop through matches and resize array
i = 0
For Each regexMatch In regexMatchCollection
ReDim Preserve strMatches(2, i)
strMatches(0, i) = regexMatch.FirstIndex
strMatches(1, i) = regexMatch.Length
strMatches(2, i) = regexMatch.Value
i = i + 1
Next
End Sub

fumei
10-11-2007, 08:33 AM
Tony,

could you expand your comment re: word and sentence objects?

There is, of course, a Word object - it is just that it is Word and not A word. Also there is not a Sentence object.What do you mean it is Word, not A Word?

Dim aWord As Word

does NOT work, at least in 2002.

Debug.Print ActiveDocument.Words(1)
Debug.Print ActiveDocument.Sentences(1)

both return values. So how are you saying Sentence is not an object, but Word is?

I stand corrected that Sentence (singular) is not an object, but how can Word be an object? Is not "Word" the container, ie. the application itself.

If you want to run through the "words" (or "sentence") of a range, selection, whatever, you have to declare your variable as Variant, or Object.

So, it seems to me that there are either BOTH a Word and Sentence object...or neither.

There are Words and Sentences collections. However, are they really collections? I usually think of collections as collected discrete singular objects. Both Words, and Sentences seem derived to me. Unlike, say Paragraphs, which clearly contains Paragraph (singular) objects. You can declare ONE paragraph.

Dim whatever As Paragraph is legitimate

Dim whatever As Word is not
Dim whatever as Sentence is not.

You can, of course use Dim whatever As WordDOTSomething, but that is declaring an child object from the container Word (the application).

I am willing to understand and learn.

TonyJollans
10-12-2007, 03:18 AM
True, you cannot declare anything as Word but it is still an object - the granddaddy of all objects - but I was being slightly flippant :)

As you have noted, there is no Sentence object in the same way there is no Word object - the Sentences collection contains Range objects.

I doubt I can teach you anything in this area :-)

fumei
10-12-2007, 01:24 PM
Just like the Words collection contains Range objects.

What I find odd, in that they are not exposed, are the delimiters.

Range.Words will consider ") " a word, and indeed count it as such. It counts the paragraph mark as a word. It counts the period at the end of a sentence as a separate word.

But a WordCount does not. The delimiters are stripped off internally...deep down in the bowels of the application, where we....can't....see.

mfegyver
10-31-2007, 07:44 PM
good question, Joseph, many thanks for it. was also my problem for today.
unfortunly your code didn't work with me :banghead: .
it?s states:

"user defined-type not defined"
and i don't know what i have to do to define it.
i?ve to learn to much to undesrtand your teachings...

but no problem at all, i?m happy my first learning to code in word and it is working and very usefull, thanks to your question, Joseph and special thanks to Garry for your code, that helps almost 95% of my work.

(i've added a ridiculous Selection.WholeStory in the beggining)

also wondering, I've comments in the end of some sentences, so, wouldn't it be possible to identify the " ' " comments mark, then select 10 or 20 characteres rightside from it and paint ?
(at excel it would be so easy...)

many thanks to all
marcelo

lucas
10-31-2007, 08:13 PM
Hi marcelo,
You should read these comments in Joseph's code:
' *************************************************************************** *
' Author:
' Date:
' Purpose: Return indices of matches for a regEx pattern on a string passed
' Pre-Conditions:
' Post-Conditions:
' References: Microsoft VBScript Regular Expressions 5.x
' *************************************************************************** *
Notice the one that says references. You need to go to tools-References in the visual basic editor and find the "Microsoft VBScript Regular Expressions 5.x" library and put a check next to it then run the code. That will take care of your error. Be sure to select the code on the regular sheet that you wish to format before you run it. The 5.x will not actually be 5.x It will be 5.6 or 5.7, etc. determined by your version of excel....it will work though.

Joseph, It looks pretty good but I just don't like the look of code in a Word document....

malik641
10-31-2007, 08:40 PM
Marcello,

Thanks. It was a fun piece of code to write. Good use of Regular Expressions :)

As lucas pointed out, just set the reference to RegEx and it should work. Also, be sure to copy the code ONLY from the VBE, then paste into word (word has funny quotation marks and apostraphes that the code currently doesn't handle...which I had in there, but I figured if the code was right in the VBE, why change it?).


also wondering, I've comments in the end of some sentences, so, wouldn't it be possible to identify the " ' " comments mark, then select 10 or 20 characteres rightside from it and paint ?
(at excel it would be so easy...) My code handles that. When you get it running you'll see. The difference with my approach is that when I find an apostraphe, I make sure it's not inside quotation marks (because that would be a string), and if it's not I just color from the apostraphe onto the end of the line. It's that easy :)


Joseph, It looks pretty good but I just don't like the look of code in a Word document.... Thanks. I was wondering when I was going to get some feedback ;)

It's more of a representation thing for me. This would be really nice for Word tutorials on VBA. Just my opinion.

malik641
11-16-2007, 01:27 PM
So, Tony, Gerry, what do you think? It's been over a month since I posted the code. Is this better than a "half-a$$ed" solution?

:dunno

TonyJollans
11-16-2007, 04:44 PM
I've just had a very quick play with it.

This (near the beginning) seems rather inefficient:
For Each aWord In Selection.Range.Words
For var = 0 To UBound(MyKeywords)
' Check for As keyword to highlight next variable (next word)
If aWord = "As " Then
Set NextWord = aWord.Next
NextWord.Expand unit:=wdWord
NextWord.Font.Color = wdColorBlue
End If

If Trim(aWord) = MyKeywords(var) Then
aWord.Font.Color = wdColorBlue
End If
Next
Next
Two points - the check for "As" should be outside the inner loop - and you could terminate the inner loop (and iterate the outer one) when you have found the word.

With (and End With) doesn't colour as per the VBE.

I don't know when I'd use this so it's a bit hard of me to say, but I'd prefer if the bits coloured in red didn't also have red quotes - in other words I would prefer "Header" to "Header".

It doesn't seem to colour On Error GoTo correctly. I see, now that the list of keywords is incomplete so no more of this type of comment.

"End" in "End:=(Selection.Range.Start)" is wrongly coloured

I'll have to look at the Regex properly later.