Consulting

Results 1 to 18 of 18

Thread: How to detect certain characters in a selection/string?

  1. #1

    How to detect certain characters in a selection/string?

    Hi, I'm making a macro that will move whatever text I have selected to the beginning of the sentence, capitalize it, then de-capitalize the original first word of the sentence. The code is below:

    Sub MoveToBeginningSentence()
        Application.ScreenUpdating = False
        
        Selection.Cut
        Selection.MoveLeft Unit:=wdSentence, Count:=1, Extend:=wdMove
        Selection.Collapse Direction:=wdCollapseStart
        Selection.Paste
        'Move text to the beginning
    
    
        Selection.MoveRight Unit:=wdWord, Count:=1, Extend:=wdExtend
        Selection.Range.Case = wdLowerCase
        'Normalize old word
        
        Selection.MoveLeft Unit:=wdSentence, Count:=1, Extend:=wdMove
        Selection.MoveRight Unit:=wdWord, Count:=1, Extend:=wdExtend
        Selection.Range.Case = wdTitleWord
        'Capitalize new beginning
    End Sub
    However, if the sentence has a punctuation mark of some kind at the beginning, there will be 2 issues.

    Take this sentence as an example: "We haven't seen her today."

    If I select today and apply the macro, this will be the new sentence: Today 'We haven't seen her today.'

    As you can see, the word Today got pushed outside of the quotation mark. And since the mark is recognized as an entire word by itself, the macro won't select We and make it a lowercase word.

    I've come up with a possible solution:
    • Before pasting, have the macro select the first word of the sentence and see if it's either ' or ". If that's the case, move right 1 character, then paste. If not, deselect, go back to the beginning, and paste.
    • After pasting, select the next word, see if it's either ' or ". If that's the case, select the next word to the right and de-capitalize. If not, de-capitalize right away.


    The problem is I don't know how to detect specific characters in a string/selection. Is there any way to do that?

    And if you have any better solution for those issue, I'm all ears.

  2. #2
    Knowledge Base Approver VBAX Guru macropod's Avatar
    Joined
    Jul 2008
    Posts
    4,435
    Location
    And what are you going to do if the first word should be capitalised even when it's not the first word in the sentence? For example:
    Mark hasn't seen her today.
    Last edited by macropod; 01-18-2018 at 05:27 AM.
    Cheers
    Paul Edstein
    [Fmr MS MVP - Word]

  3. #3
    I'll just have to re-capitalize it. In my experience translating foreign work (the macro is to help me translate faster, btw), sentences where first word needs to stay capitalized appear less frequent than those without them. Even if one were to turn up, I only have to activate the macro and recapitalize 1 word (2 steps), instead of having to cut the phrase, move it to the beginning, paste it, and recapitalize it (4 steps).

  4. #4
    Knowledge Base Approver VBAX Guru macropod's Avatar
    Joined
    Jul 2008
    Posts
    4,435
    Location
    Try:
    Sub Demo()
    With Selection
      Do While .Characters.First Like "[ " & Chr(34) & Chr(147) & Chr(11) & vbCr & vbTab & ".!?]"
        .MoveStart wdCharacter, 1
      Loop
      Do While .Characters.Last Like "[ " & Chr(34) & Chr(148) & Chr(11) & vbCr & vbTab & ".!?]"
        .MoveEnd wdCharacter, -1
      Loop
      MsgBox .Text
    End With
    End Sub
    Cheers
    Paul Edstein
    [Fmr MS MVP - Word]

  5. #5
    Shouldn't we use the If function instead of loop? And what's the message box for?

  6. #6
    I tried to adapt your code to mine but it didn't work. The same problem still exists, as if the macro couldn't detect the 2 quotation marks.

    Here's my updated code:

    Sub MoveToBeginningSentence() 
        Application.ScreenUpdating = False 
         
        Selection.Cut 
        Selection.MoveLeft Unit:=wdSentence, Count:=1, Extend:=wdMove 
        Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdExtend 
        If Selection.Characters.First Like "[ " & Chr(34) & Chr(147) & Chr(11) & vbCr & vbTab & ".!?]" Then
            Selection.MoveLeft Unit:=wdSentence, Count:=1, Extend:=wdMove 
            Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdMove 
            Selection.Paste 
        
            Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdExtend 
            Selection.Range.Case = wdLowerCase 
    
            Selection.MoveLeft Unit:=wdSentence, Count:=1, Extend:=wdMove 
            Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdMove 
            Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdExtend 
            Selection.Range.Case = wdUpperCase 
        Else
            Selection.MoveLeft Unit:=wdSentence, Count:=1, Extend:=wdMove 
            Selection.Paste 
    
            Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdExtend 
            Selection.Range.Case = wdLowerCase 
    
            Selection.MoveLeft Unit:=wdSentence, Count:=1, Extend:=wdMove 
            Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdExtend 
            Selection.Range.Case = wdUpperCase 
        End If
    End Sub

  7. #7
    Knowledge Base Approver VBAX Guru macropod's Avatar
    Joined
    Jul 2008
    Posts
    4,435
    Location
    Quote Originally Posted by vkhu View Post
    Shouldn't we use the If function instead of loop? And what's the message box for?
    Maybe you should try the code as-is, then do some thinking about why I used loops instead of condescendingly questioning my approach...
    I'd have though it pretty obvious the message box is just there to demonstrate the result.

    Quote Originally Posted by vkhu View Post
    I tried to adapt your code to mine but it didn't work.

    That's hardly surprising, given the way you 'adapted' it.
    Cheers
    Paul Edstein
    [Fmr MS MVP - Word]

  8. #8
    Sorry if that comes off as condescending, but I genuinely don't get why it's a loop and not an in else statement, and why the message box is there. Once again, why do you need to use loop and not if else? What's wrong with the way I adapt it?

  9. #9
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,335
    Location
    You don't have to use a loop as your code illustrates. You don't have to use selection either as I hope this will illustrate:

    Sub ScratchMacro()
    'A basic Word macro coded by Greg Maxey, http://gregmaxey.com/word_tips.html, 1/20/2018
    Dim oROI As Range
    Dim oRng As Range
      Set oROI = Selection.Range
      Set oRng = oROI.Sentences(1)
      With oRng
        Do While .Characters.First Like "[ " & Chr(34) & Chr(147) & Chr(11) & vbCr & vbTab & ".!?]"
          .MoveStart wdCharacter, 1
        Loop
        .Characters(1).Case = wdLowerCase
        .Collapse wdCollapseStart
        oROI.Cut
        .Paste
        .Characters(1).Case = wdUpperCase
      End With
    lbl_Exit:
      Exit Sub
    End Sub
    Greg

    Visit my website: http://gregmaxey.com

  10. #10
    Knowledge Base Approver VBAX Guru macropod's Avatar
    Joined
    Jul 2008
    Posts
    4,435
    Location
    Quote Originally Posted by gmaxey View Post
    You don't have to use a loop as your code illustrates.
    But, as your own code amply illustrates, a loop is the most efficient way of achieving the desired result. My sample code has two loops: one to exclude unwanted characters from the start; the other to exclude unwanted characters from the end.
    Cheers
    Paul Edstein
    [Fmr MS MVP - Word]

  11. #11
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,335
    Location
    Come on Paul. I'm really not interested in throwing into a brouhaha over it. Certainly I agree with the efficiencies of a loop and if I had an issue with a your loop then I wouldn't have used it. That doesn't change the fact that in cases where there is only one troublesome character (in this case the opening quotation mark at the start of the sentence) then the IF statement as vkhu used does work.


    vkhu. I'm not going to fault Paul or his methods. He is a very smart guy. In this case his code illustrated how to efficiently trim unwanted characters from the start and end of a selection. Consider this text (yes, the quotation marks are meant to be part of the text) where you select the entire line including the beginning quotation mark and ending paragraph marks:

    "Watch out!"

    Then run Paul's code below and then the DemoII version using an If statement instead then the DemoIII version using multiple IF statements. You should readily see that while an IF statement can work (and did in your case), that it is best to use code that will work in any case (a loop)

    Sub Demo()
      With Selection
        Do While .Characters.First Like "[ " & Chr(34) & Chr(147) & Chr(11) & vbCr & vbTab & ".!?]"
          .MoveStart wdCharacter, 1
        Loop
        Do While .Characters.Last Like "[ " & Chr(34) & Chr(148) & Chr(11) & vbCr & vbTab & ".!?]"
          .MoveEnd wdCharacter, -1
        Loop
        MsgBox .Text
      End With
    End Sub
    
    Sub DemoII()
      With Selection
        If .Characters.First Like "[ " & Chr(34) & Chr(147) & Chr(11) & vbCr & vbTab & ".!?]" Then
          .MoveStart wdCharacter, 1
        End If
        If .Characters.Last Like "[ " & Chr(34) & Chr(148) & Chr(11) & vbCr & vbTab & ".!?]" Then
          .MoveEnd wdCharacter, -1
        End If
        MsgBox .Text
      End With
    End Sub
    
    Sub DemoIII()
      With Selection
        If .Characters.First Like "[ " & Chr(34) & Chr(147) & Chr(11) & vbCr & vbTab & ".!?]" Then
          .MoveStart wdCharacter, 1
        End If
        If .Characters.Last Like "[ " & Chr(34) & Chr(148) & Chr(11) & vbCr & vbTab & ".!?]" Then
          .MoveEnd wdCharacter, -1
        End If
        If .Characters.Last Like "[ " & Chr(34) & Chr(148) & Chr(11) & vbCr & vbTab & ".!?]" Then
          .MoveEnd wdCharacter, -1
        End If
        If .Characters.Last Like "[ " & Chr(34) & Chr(148) & Chr(11) & vbCr & vbTab & ".!?]" Then
          .MoveEnd wdCharacter, -1
        End If
        MsgBox .Text
      End With
    End Sub
    Greg

    Visit my website: http://gregmaxey.com

  12. #12
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,335
    Location
    ... and don't forget the can of worms: Mr. Smith spent $1,234.56 at Dr. John's Grocery Store, to buy: 10.25kg of potatoes; 10kg of avocados; and 15.1kg of Mrs. Green's Mt. Pleasant macadamia nuts.
    Greg

    Visit my website: http://gregmaxey.com

  13. #13
    Knowledge Base Approver VBAX Guru macropod's Avatar
    Joined
    Jul 2008
    Posts
    4,435
    Location
    Greg,

    I'm "not interested in throwing into a brouhaha over it", either. The whole point of the loops in the code I posted was to accommodate the possibility that the user has selected multiple unwanted characters at the start and/or the end of the selection.

    All vkhu could respond with was "Shouldn't we use the If function instead of loop? And what's the message box for?", without apparently ever trying the code I provided so he might understand what it was doing, then complaining "I tried to adapt your code to mine but it didn't work" when he didn't bother with the loop.
    Cheers
    Paul Edstein
    [Fmr MS MVP - Word]

  14. #14
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,335
    Location
    Paul,

    Ok. Regarding the response. Yes, I suppose it could have been couched in better terms. However, the initial problem was 1) a sentence structured like "We haven't seen her today." 2) I select the word "today" and run the macro 3) the hoped for result is "Today we haven't seen her." 4) the actual (undesirable) result is Today "We haven't seen her."

    Your code while a textbook example of an efficient method of removing defined leading/trailing characters from selected text was not a readily apparently solution to the problem\question posted (or was it and I'm missing something?) I did run your code and I do understand what it is doing, but the result of running it with "today" selected in the text is just a message box returning "today" (or whatever text is selected).

    I saw your code (or the first part of it) as a key step in the solution to the actual problem (that is handling any defined characters at the start of the sentence range containing the selected text). Characters at the end of the sentence didn't matter. I'm just being honest Paul. With less experience, I may have been sorely perplexed by your proposed solution and may have had questions of my own. I can only hope that I would have framed them in a manner that would not have been construed as condescending.
    Greg

    Visit my website: http://gregmaxey.com

  15. #15
    Knowledge Base Approver VBAX Guru macropod's Avatar
    Joined
    Jul 2008
    Posts
    4,435
    Location
    Hi Greg,

    The snippet I provided in post #4 was only ever intended to address the OP's question:
    The problem is I don't know how to detect specific characters in a string/selection. Is there any way to do that?
    It was never intended to be the full solution.
    Cheers
    Paul Edstein
    [Fmr MS MVP - Word]

  16. #16
    Quote Originally Posted by macropod View Post
    All vkhu could respond with was "Shouldn't we use the If function instead of loop? And what's the message box for?", without apparently ever trying the code I provided so he might understand what it was doing, then complaining "I tried to adapt your code to mine but it didn't work" when he didn't bother with the loop.
    This might come as a shock to you, macropod, but I'm part of the the millions of people jumping into this with no background in coding whatsoever. You could have given me an alphabet or the formula for the cure for cancer in VBA, and without any explanation, I would have found them equally baffling. I don't get your code. It's that plain and simple.

    And you were wrong in assuming I never bother with the loop. I put it in a new macro, and all I see is it giving me a message box. That's it. Nothing more. I read over it again but I simply don't get what is supposed to do what. If I can't understand it, how can I use it? Should I put it at the top of the code? At the bottom? What's the deal with all of the loops? How do they solve the problem? Do I split the code in half? Which point should be split? Do I need to paste them in several places?... What's more, if you read over the way I phrase the problem, I'm clearly stuck in the mindset that this problem can only be solve by telling the macro: "IF you see a parenthesis, THEN go back a character. IF it's something ELSE, just paste." The code you gave have nothing but bunch of loop which I understand as telling the macro to: "Do this again and again and again and again," and I got thrown off completely. So without asking for clarification, how could I use it?

    Up till that point, the only thing close to an explanation I can find in your posts is the word "Try." You even said it yourself this isn't intended as a full answer. If it's anything more complicated than a copy-and-paste-and-hit-run, I need to understand it to apply it. Since I didn't understand it, and you didn't bother to clarify it, I had to work out by myself how to make use of it. It's like me throwing you a pair of chopsticks to eat sushi without explanation. If you've never held chopsticks before in your life, and I refuses to explain how chopsticks work, would it be any surprise that you would stab at the sushi rolls like you're holding a knife? Is that you being spiteful toward my culture, or it's just that you genuinely don't get what's the proper use for them?

  17. #17
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,335
    Location
    vkhu,

    Hoping that everything is off of your chest and Paul's, do you have any other questions regarding to solution provided to your original post?
    Greg

    Visit my website: http://gregmaxey.com

  18. #18
    Nothing at the moment. Your code worked like a charm, gmaxey. I'm digging through some documentation on range object and loop to better understand it, but I got the gist of the logic behind it.

Posting Permissions

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