Consulting

Page 2 of 2 FirstFirst 1 2
Results 21 to 29 of 29

Thread: Select a Sentence

  1. #21
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    I can see there's room for improvement by utilizing the .Words collection as well, but going to leave that for now.

  2. #22
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,340
    Location
    Jason,

    I added a Test #6 and made a few other minor changes. The rest is just style.

    Works as before with the test sentences we have been using.

    My grammar is not much better than my spelling. Test #6 handles:

    Joe shouted, “Throw me the ball!” before running over the edge of thecliff.

    .... which I think should be treated a one sentence.

    [VBA]Option Explicit
    Private m_strFollowingText As String
    Private m_strPrecedingText As String
    Private m_oRngParagraph As Range
    Private m_colSentencesDeduced As Collection
    '************************************************************************** **********************
    Public Sub BoldAFirstSentence()
    If SelectASentence(1) = True Then
    Selection.Font.Bold = True
    End If
    End Sub
    '************************************************************************** **********************
    'Select the sentence the cursor is currently in (or the first sentence in the selected range)
    Public Sub SelectCurrentSentence()
    Dim i As Long
    Dim oRngDeducedSentence As Range
    'Dim m_colSentences As Collection
    'If not for this line, nothing will get selected if the selection spans two sentences.
    Selection.Collapse wdCollapseStart
    Set m_colSentencesDeduced = fGetRealSentences(Selection.Range)
    i = 1
    For Each oRngDeducedSentence In m_colSentencesDeduced
    i = i + 1
    If Selection.Range.InRange(oRngDeducedSentence) Then
    Select Case True
    Case oRngDeducedSentence.End = ActiveDocument.Range.End
    oRngDeducedSentence.MoveEnd wdCharacter, -1
    Case i > 1 And m_colSentencesDeduced.Count > 1 And oRngDeducedSentence.End = Selection.Paragraphs(1).Range.End
    oRngDeducedSentence.MoveEnd wdCharacter, -1
    End Select
    oRngDeducedSentence.Select
    Exit For
    End If
    Next oRngDeducedSentence
    lbl_Exit:
    Exit Sub
    End Sub
    '************************************************************************** *********************
    'Target indexed sentence in first paragraph defined by the selection (See call above).
    Public Function SelectASentence(Optional lngIndex As Long = 1) As Boolean
    'Establish boundry.
    Set m_oRngParagraph = Selection.Paragraphs(1).Range
    'Get collection of "real" sentences
    Set m_colSentencesDeduced = fGetRealSentences(m_oRngParagraph)
    On Error Resume Next
    m_colSentencesDeduced(lngIndex).Select
    'If unable to select then it must not exist.
    If Err.Number = 0 Then
    SelectASentence = True
    Else
    SelectASentence = False
    MsgBox "A sentence defined by the passed index " & lngIndex & " does not exist in the seleciton.", vbInformation
    End If
    End Function
    '************************************************************************** *********************
    'Creates a collection of "real" (or hopefully more realistic) sentences in the first paragraph
    'of the passed range based on the built-in Sentences collection object
    Public Function fGetRealSentences(oRngSelectionStart As Range) As Collection
    Dim colSentences As Sentences
    Dim oRngSentence As Range
    Dim oRngEndMark As Range
    Dim oRngSentenceDeduced As Range

    'Initialize our collection variable.
    Set m_colSentencesDeduced = New Collection
    'Fix a boundry.
    Set m_oRngParagraph = oRngSelectionStart.Paragraphs(1).Range
    'Get collection of Word-Native defined sentences (a collection of ranges).
    Set colSentences = m_oRngParagraph.Sentences

    'Initialize our new sentence, so that it has a good start
    Set oRngSentenceDeduced = colSentences(1)

    'If Word returns a single sentence then a single sentence it is.
    If colSentences.Count = 1 Then
    m_colSentencesDeduced.Add m_oRngParagraph
    Else
    'Word returns multiple sentences. But is this true?
    'Loop through the MS-determined "sentences" to find out.
    For Each oRngSentence In colSentences
    With oRngSentence.Characters.Last
    Set oRngEndMark = .Previous
    'If out of bounds, then adjust backwards.
    'This deals with MS defaulting to including blank paragraphs in the concept of a "Sentence"
    If .InRange(m_oRngParagraph) = False Then
    Do Until oRngEndMark <> vbCr
    Set oRngEndMark = oRngEndMark.Previous
    Loop
    End If
    'Now see if our MS-identified sentence ender is "really" a sentence ender.
    'If it is then add to range.
    If fIsSentenceEnder(oRngEndMark) Then
    'Do we need to adjust this forward or backward?
    oRngSentenceDeduced.End = oRngEndMark.End
    'Get rid of preceeding whitespaces before adding to our collection of sentences
    Do Until fIsWhiteSpace(oRngSentenceDeduced.Characters.First) = False
    oRngSentenceDeduced.MoveStart wdCharacter, 1
    Loop
    'Should we include trailing whitespaces in our sentence definition (MS does)
    Do
    If oRngSentenceDeduced.Characters.Last <> vbCr Then
    oRngSentenceDeduced.MoveEnd wdCharacter, 1
    Else
    Exit Do
    End If
    Loop Until fIsWhiteSpace(oRngSentenceDeduced.Characters.Last.Next) = False

    'Add deduced sentence to collection.
    m_colSentencesDeduced.Add oRngSentenceDeduced.Duplicate
    'Redefine start.
    oRngSentenceDeduced.Collapse wdCollapseEnd
    End If
    End With
    Next oRngSentence
    End If
    'Return the collection
    Set fGetRealSentences = m_colSentencesDeduced
    lbl_Exit:
    End Function
    '************************************************************************** *********************
    'Validate sentence ender.
    Public Function fIsSentenceEnder(oRngEndMarkPassed As Range) As Boolean
    Dim i As Long
    Dim oRngParagraph As Range
    Dim strEndings_Not As String
    Dim strEndings_Maybe As String

    'Preliminary list. Adjust as required - utilize a Split on the delimiter "|" later.
    strEndings_Not = "Mr|Mrs|Ms|Dr"
    strEndings_Maybe = "Jr|Esq|MD"

    'Define parent paragraph (which is the absolute bound).
    Set oRngParagraph = oRngEndMarkPassed.Paragraphs.First.Range

    'Test #1 - If we're at the end of our paragraph, it's a sentence ender
    If oRngEndMarkPassed.End = oRngEndMarkPassed.Paragraphs(1).Range.End Then
    fIsSentenceEnder = True
    GoTo lbl_Exit
    End If

    'Determine what comes before and after ending mark.
    m_strPrecedingText = fGetText(oRngEndMarkPassed, False)
    m_strFollowingText = fGetText(oRngEndMarkPassed, True)

    'Test #2 - If nothing follows then it must be the end of a sentence. (Jason this might be redundant??)
    If m_strFollowingText = "" Then
    fIsSentenceEnder = True
    GoTo lbl_Exit
    End If

    'Test #3 (require at least one following "white space" character
    If fIsWhiteSpace(oRngEndMarkPassed.Next) = False Then
    fIsSentenceEnder = False
    GoTo lbl_Exit
    Else
    'If it is followed by more multiple whitespace characters (e.g., two spaces) the assume a sentence ender.
    If fIsWhiteSpace(oRngEndMarkPassed.Next.Next) Then
    fIsSentenceEnder = True
    GoTo lbl_Exit
    End If
    End If

    'Test #4 (Mr. John Smith)
    'Test using array of definite non-sentence ending periods (add to this as needed)
    If fPhraseMatch(strEndings_Not, oRngEndMarkPassed) = 1 Then
    fIsSentenceEnder = False
    GoTo lbl_Exit
    End If

    'Test #5 (John Smith Esq.)
    'Similar test, although these are the "maybes", which necessitate an extra check.
    Select Case fPhraseMatch(strEndings_Maybe, oRngEndMarkPassed, True)
    Case 1
    fIsSentenceEnder = True
    GoTo lbl_Exit
    Case 2
    fIsSentenceEnder = False
    GoTo lbl_Exit
    Case Else
    'Keep evaluating.
    End Select

    'Test #5 ( A.) -- a single capital letter preceded by white space, assume an initial?
    If fIsWhiteSpace(oRngEndMarkPassed.Previous.Previous) Then
    If oRngEndMarkPassed.Previous.Text Like "[A-Z]" Then
    fIsSentenceEnder = False
    GoTo lbl_Exit
    End If
    End If

    'Test #6 - Does the following text begin a natural sentence?
    '(1) Begin a paragraph.
    '(2) Begin with a capital letter or number.
    '(3) Begin with a quotation mark followed by a capital letter or number.
    Select Case Asc(Left(m_strFollowingText, 1))
    Case 13

    Case 11
    Select Case Asc(Mid(m_strFollowingText, 2, 1))
    Case 48 To 57, 65 To 90

    Case 34, 147, 148
    Select Case Asc(Mid(m_strFollowingText, 3, 1))
    Case 48 To 57, 65 To 90

    Case Else
    fIsSentenceEnder = False
    GoTo lbl_Exit
    End Select
    Case Else
    fIsSentenceEnder = False
    GoTo lbl_Exit
    End Select
    Case 48 To 57, 65 To 90

    Case 34, 147, 148
    Select Case Asc(Mid(m_strFollowingText, 2, 1))
    Case 48 To 57, 65 To 90

    Case Else
    fIsSentenceEnder = False
    GoTo lbl_Exit
    End Select
    Case Else
    fIsSentenceEnder = False
    GoTo lbl_Exit
    End Select

    'Unless there are more test discovered later then assume yes.
    fIsSentenceEnder = True
    lbl_Exit:
    Exit Function
    End Function
    '************************************************************************** **************************
    'Check the passed character to see if it is a "white space" character.
    Public Function fIsWhiteSpace(oRngCharacter As Range) As Boolean
    'If it doesn't exist, then it isn't whitespace!
    If Not oRngCharacter Is Nothing Then
    Select Case Asc(oRngCharacter.Text)
    Case 9, 32, 160, 13, 11
    fIsWhiteSpace = True
    Case Else
    fIsWhiteSpace = False
    End Select
    End If
    lbl_Exit:
    Exit Function
    End Function
    '************************************************************************** **************************
    'Check to the passed in phrase against any matching phrases.
    'should this be case sensitive or not?
    'Returns 1 if found a match, and a sentence-ending period
    'Returns 2 if found a match, and not a sentence-ending period (based on upper case alpha letter)
    'returns 0 if no match found
    Public Function fPhraseMatch(sAbbreviations As String, oRngEndMarkPassed As Range, _
    Optional bMightBeEnders As Boolean = False) As Long
    Dim arrAbbreviations() As String
    Dim i As Long
    Dim j As Long

    arrAbbreviations = Split(sAbbreviations, "|")
    For i = 0 To UBound(arrAbbreviations)
    'Match so far...
    If m_strPrecedingText = arrAbbreviations(i) Then
    'If no further tests, have a match.
    If bMightBeEnders = False Then
    fPhraseMatch = 1
    Else
    'Check rest of maybes.
    For j = 0 To UBound(arrAbbreviations)
    If m_strFollowingText = arrAbbreviations(j) Then
    'Match found, not a sentence ending period
    fPhraseMatch = 2
    GoTo lbl_Exit
    End If
    Next j

    Select Case Asc(Left(m_strFollowingText, 1))
    'New paragraph, A-Z or number.
    Case 13, 48 To 57, 65 To 90
    fPhraseMatch = 1
    Case 34, 147, 148
    Select Case Asc(Mid(m_strFollowingText, 2, 1))
    Case 48 To 57, 65 To 90
    fPhraseMatch = 1
    Case Else
    fPhraseMatch = 2
    End Select
    Case Else
    fPhraseMatch = 2
    End Select
    End If
    Exit For
    End If
    Next i
    lbl_Exit:
    Exit Function
    End Function
    '************************************************************************** *********************
    'Returns text immediately following or immediately preceding the range bound by our "white space" concept
    Public Function fGetText(rngWhere As Range, Optional bGetFollowing As Boolean) As String
    Dim oRngWorking As Range
    Dim strReturn As String
    Set oRngWorking = rngWhere.Duplicate
    If bGetFollowing Then
    oRngWorking.Collapse wdCollapseEnd
    'Avoid infinite loops.
    If Not oRngWorking.Characters.Last.Next Is Nothing Then
    Do Until fIsWhiteSpace(oRngWorking.Characters.Last.Next)
    oRngWorking.MoveEnd wdCharacter, 1
    Loop
    End If
    strReturn = oRngWorking.Text
    Else
    oRngWorking.Collapse wdCollapseStart
    'Avoid infinite loops.
    If Not oRngWorking.Characters.First.Previous Is Nothing Then
    Do Until fIsWhiteSpace(oRngWorking.Characters.First.Previous)
    oRngWorking.MoveStart wdCharacter, -1
    Loop
    End If
    strReturn = oRngWorking.Text
    End If
    'Trim it, and remove the ending mark.
    strReturn = Trim(strReturn)
    strReturn = Replace(strReturn, ".", "")
    strReturn = Replace(strReturn, "?", "")
    strReturn = Replace(strReturn, "!", "")
    fGetText = strReturn
    lbl_Exit:
    Exit Function
    End Function
    [/VBA]
    Greg

    Visit my website: http://gregmaxey.com

  3. #23
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    After a good bit of back and forth between Greg and I... here's a demo template utilizing a new class for sentences.

    Bernadette, this is way more than you actually asked for. However, this may provide utility for others as well.
    Attached Files Attached Files

  4. #24
    Wow guys, thank you for the contribution...I, for one, find utility.

  5. #25
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    And here is a slightly more explanatory template, in that it has some buttons to click on the Quick Access Toolbar, as well as a demonstration of the difference between how the builtin Microsoft Sentences are defined, and how this code goes.

    If anyone wants to use this, the ThisApplication isn't really necessary (as that's a separate concept Greg and I were testing)... you'd just need to import the cSentences class into your project, and then use code based on the samples in the mMain module.

    Note: copying the text of the class and pasting into your own version of a cSentences class will work, except that you'll lose a hidden attribute defining default member of the class. That's a whole lot of blah blah-- basically, import (or drag copy) the cSentences class module from this project to yours if you want to use it.
    Attached Files Attached Files

  6. #26
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    Greg Maxey pointed out a flaw in the above project.

    J. E. B. Stuart was a general in the CSA.

    If that sentence is placed at the start of the document, it creates infinite loop possibilities. Don't have a total fix for that yet, so just wanted to throw up the warning that CTRL+BREAK may be necessary for anyone exploring the above code.

  7. #27
    Wow! You guys went above and beyond figuring this out. I have not tried the code yet but I sure didn't think it would be this complicated. I used to use WordPerfect and PerfectScript and it knew how to select a sentence even if there were abbreviations. Thanks so much for looking at this problem!

  8. #28
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,340
    Location
    And we're done yet!! Check back as Jason and I are still polishing the cannonball.
    Greg

    Visit my website: http://gregmaxey.com

  9. #29
    VBAX Newbie
    Joined
    Oct 2014
    Posts
    1
    Location

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •