Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 954
  • Last Modified:

Macro: TRIM spaces & tabs, and use Wildcards in a CASE statement

Hi,

In a Word macro, I'm determining the first word of multiple paragraphs, and, based on what that word is, doing something slightly different on the paragraph.  Thus, I set the word to a variable and then do a CASE statement.

I am getting the first word with the following code:

ActiveDocument.Paragraphs(i).Range.Select
firstword = Trim(Selection.Range.Words(1))

However, sometimes the first word is "S" followed by 4 digits, and this word may or may not be preceded by spaces or a tab character.  I'm not certain whetherTRIM is removing spaces/tabs in front of these particular lines of text, because I'm not certain if I'm using wildcards properly in my CASE statement.

Here's what I'm using:    Case "S[0-9]{1,2,3,4}"

Will that syntax work in the CASE statement? And will the TRIM function result in the "S" number being identified as the first word of the line if it's got multiple spaces or a tab in front of it?

Thanks for any guidance!

--Galisteo8
0
Galisteo8
Asked:
Galisteo8
  • 7
  • 6
  • 3
3 Solutions
 
Patrick MatthewsCommented:
Try something like:

If InputString Like "S####" Then
0
 
Galisteo8Author Commented:
Hi!

And try using that where?
0
 
Patrick MatthewsCommented:
Galisteo8,

Instead of your case structure, use:

If firstword Like "S####" Then
    'code here
ElseIf firstword Like "T####" Then
    'code here
ElseIf ...
    'Code here
Else
    'code
End If

Regards,

Patrick
0
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
GrahamSkanCommented:
First of all, Wildcards are only used in Find operations.
Secondly, by definition,  the 'Word' range does not contain spaces, but might have a single trailing space.
Thirdly, the word can contain digits, so

 Rtrim$(ActiveDocument.Paragraphs(i).Range.Words(1).text) will retutn the text of the first word of the i th paragraph.

0
 
GrahamSkanCommented:
To test to see if it begins with an 's' simply test the first character. The structure of the categorising test procedures will depend on the variety of things that are to be tested for.

Sub fgfg()
    Dim FirstWord As String
    Dim i As Integer
   
    FirstWord = RTrim$(ActiveDocument.Paragraphs(1).Range.words(1).Text)
    Select Case UCase$(Left$(FirstWord))
        Case "S"
            'S process
        Case Else
    End Select

End Sub

0
 
Patrick MatthewsCommented:
GrahamSkan said:
>>First of all, Wildcards are only used in Find operations.

Graham, try this in the Immediate window:

?"S1234" Like "S####"

It will return True.  (And ?"S12x4" Like "S####" will return False, as expected.)

You can use wildcards in a Like comparison.

Now, I inferred from the question that we needed to see S plus four digits, not just 'begins
with S'.  I might be wrong, of course...
0
 
Patrick MatthewsCommented:
Galisteo8,

The reason why I used If...ElseIf...Else is because I do not think you are allowed to use the
Like operator in a Select Case construct.  At least, if you are allowed, I've never figured
out how :)  However, anything Select Case can do, If...ElseIf...Else can do also.

Regards,

Patrick
0
 
Galisteo8Author Commented:
Thanks for the suggestions thus far.  I'm swapping out to the If-ElseIf construction.

Now, with that done.... I am STILL not getting the first word of any lines that begin with a tab character or multiple spaces.  The line whose first word is S### is indented by a tab OR by several spaces, and Trim (as I had it) and Rtrim (as Grahama suggested) are still giving me a first word of "".  What function will ignore all the "white space" characters and give me the REAL first word of the line?
0
 
GrahamSkanCommented:
Unfortunately Word treats a Tab as a word in  its own right. You will probably have to create you own definition of an acceptable Word.

This macro will find in each paragraph the first word with two characters or more composed entirely of numbers and letters.

Sub GetFirstWords()
    Dim p As Integer
    Dim rng As Range
    Dim para As Paragraph
    For p = 1 To ActiveDocument.Paragraphs.Count
        Set para = ActiveDocument.Paragraphs(p)
        Set rng = para.Range
        With rng.Find
            .MatchWildcards = True
            .Text = "<[A-Za-z0-9]{2,}>"
            If .Execute() Then
                'process paragraph
            End If
        End With
    Next p
End Sub

0
 
Patrick MatthewsCommented:
Galisteo8,

Sorry, I had not accounted for the tabs.  Modfying the basic approach:

1) Add this UDF to your module:



Function RegExpFind(LookIn As String, PatternStr As String, Optional Pos, _
    Optional MatchCase As Boolean = True)

    ' For more info see: http://vbaexpress.com/kb/getarticle.php?kb_id=841

    ' This function uses Regular Expressions to parse a string (LookIn), and return matches to a
    ' pattern (PatternStr).  Use Pos to indicate which match you want:
    ' Pos omitted               : function returns a zero-based array of all matches
    ' Pos = 0                   : the last match
    ' Pos = 1                   : the first match
    ' Pos = 2                   : the second match
    ' Pos = <positive integer>  : the Nth match
    ' If Pos is greater than the number of matches, is negative, or is non-numeric, the function
    ' returns an empty string.  If no match is found, the function returns an empty string
   
    ' If MatchCase is omitted or True (default for RegExp) then the Pattern must match case (and
    ' thus you may have to use [a-zA-Z] instead of just [a-z] or [A-Z]).
   
    ' If you use this function in Excel, you can use range references for any of the arguments.
    ' If you use this in Excel and return the full array, make sure to set up the formula as an
    ' array formula.  If you need the array formula to go down a column, use TRANSPOSE()
   
    Dim RegX As Object
    Dim TheMatches As Object
    Dim Answer() As String
    Dim Counter As Long
   
    ' Evaluate Pos.  If it is there, it must be numeric and converted to Long
    If Not IsMissing(Pos) Then
        If Not IsNumeric(Pos) Then
            RegExpFind = ""
            Exit Function
        Else
            Pos = CLng(Pos)
        End If
    End If
   
    ' Create instance of RegExp object
    Set RegX = CreateObject("VBScript.RegExp")
    With RegX
        .Pattern = PatternStr
        .Global = True
        .IgnoreCase = Not MatchCase
    End With
       
    ' Test to see if there are any matches
    If RegX.test(LookIn) Then
       
        ' Run RegExp to get the matches, which are returned as a zero-based collection
        Set TheMatches = RegX.Execute(LookIn)
       
        ' If Pos is missing, user wants array of all matches.  Build it and assign it as the
        ' function's return value
        If IsMissing(Pos) Then
            ReDim Answer(0 To TheMatches.Count - 1) As String
            For Counter = 0 To UBound(Answer)
                Answer(Counter) = TheMatches(Counter)
            Next
            RegExpFind = Answer
       
        ' User wanted the Nth match (or last match, if Pos = 0).  Get the Nth value, if possible
        Else
            Select Case Pos
                Case 0                          ' Last match
                    RegExpFind = TheMatches(TheMatches.Count - 1)
                Case 1 To TheMatches.Count      ' Nth match
                    RegExpFind = TheMatches(Pos - 1)
                Case Else                       ' Invalid item number
                    RegExpFind = ""
            End Select
        End If
   
    ' If there are no matches, return empty string
    Else
        RegExpFind = ""
    End If
   
    ' Release object variables
    Set RegX = Nothing
    Set TheMatches = Nothing
   
End Function



2) Now the logic becomes something like:

firstword = RegExpFind(Selection.Text, "[a-z0-9]+", 1, False)

If firstword Like "S####" Then
    'code here
ElseIf firstword Like "T####" Then
    'code here
ElseIf ...
    'Code here
Else
    'code
End If


RegExpFind should find the first alphanumeric block, ignoring anything that is not a letter or
digit.

Regards,

Patrick
0
 
Galisteo8Author Commented:
Gents,

This is great! I can see the value of both approaches suggested.  Where Graham suggests code that will determine whether the paragraph has something readable in it (and therefore requires bordering/printing), Matthew's suggestion actually allows for the S###  text to be set to my firstword variable, so that I can explicitly handle it in the ElseIf construction.

However, in either case, the border gets placed around the text AND the leading spaces/tabs. How might I have the selection, and therefore the border, ONLY apply to the readable text in the paragraph?
0
 
Galisteo8Author Commented:
What I'm trying at the moment, in response to my own prior post, is the following, which uses RegExpFind again to determine if the first word of the paragraph is alphanumeric:

***********************
If firstword is Like "S####" Then
Selection.Paragraphs(1).Range.Select
       
If RegExpFind(Selection.Words(1), "[a-z0-9]+", 1, False) = "" Then
Selection.MoveLeft Unit:=wdWord, Count:=-1, Extend:=wdExtend
End If
       
BorderPrint
***********************

However, when I try to alter the selection (Selection.MoveLeft or .MoveRight), I can only move the right side of it, when obviously I would want to move the LEFT side of it; I am trying to move the left side one word to the right, so that the selection begins at Word(2).  If I can do that, I think I'll be good to go.  How can I move a selection like that?
0
 
Galisteo8Author Commented:
Following my prior post once more...

I've just discovered .MoveStart(offset)! So now, if the Word(1) has no alphanumerics in it, I determine how many characters it has and use that as an offset for .MoveStart.  This works for when Word(1) has one character, like a tab characer.  But in the event that Word(1) is comprised of multiple spaces, the .MoveStart doesn't work -- rather, when I step through the code, I see the cursor move to the beginning of the next paragraph!

Here's the code:

*********************************
ElseIf firstword Like "S####" Then
        Selection.Paragraphs(1).Range.Select
     
        If RegExpFind(Selection.Words(1), "[a-z0-9]+", 1, False) = "" Then
            offset = Selection.Words(1).Characters.Count
            Selection.MoveStart (offset)
        End If
       
        BorderPrint
*********************************

I've verified that offset is properly calculating the spaces.  Why won't it work if offset > 1?
0
 
Galisteo8Author Commented:
Correction: The .MoveStart doesn't work properly if offset is >2. If there are only 2 leading spaces, it works fine.

Please read prior three posts, and let me know what you think about the offset issue.
0
 
Galisteo8Author Commented:
Ah, wait -- got it!

        If RegExpFind(Selection.Words(1), "[a-z0-9]+", 1, False) = "" Then
            Offset = Selection.Words(1).Characters.Count
            Selection.MoveStart Unit:=wdCharacter, Count:=Offset
        End If

NOW the code works throughout.

Thanks to all for your help!
0
 
Patrick MatthewsCommented:
Galisteo8,

Good job on taking up mine and Graham's hints to get it working.

Graham: as always, it was a pleasure collaborating with you.

Regards,

Patrick
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 7
  • 6
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now