PDA

View Full Version : How to detect certain characters in a selection/string?



vkhu
01-18-2018, 02:45 AM
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.

macropod
01-18-2018, 05:13 AM
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.

vkhu
01-18-2018, 05:26 AM
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).

macropod
01-18-2018, 05:28 AM
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

vkhu
01-18-2018, 05:34 AM
Shouldn't we use the If function instead of loop? And what's the message box for?

vkhu
01-18-2018, 08:37 AM
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

macropod
01-18-2018, 01:30 PM
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.

I tried to adapt your code to mine but it didn't work.
That's hardly surprising, given the way you 'adapted' it.

vkhu
01-18-2018, 05:22 PM
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?

gmaxey
01-20-2018, 08:36 AM
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

macropod
01-20-2018, 02:18 PM
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.

gmaxey
01-21-2018, 07:16 AM
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

gmaxey
01-21-2018, 07:26 AM
... 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.

macropod
01-21-2018, 02:39 PM
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.

gmaxey
01-22-2018, 07:13 AM
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.

macropod
01-22-2018, 05:44 PM
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.

vkhu
01-23-2018, 03:59 AM
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?

gmaxey
01-23-2018, 06:44 AM
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?

vkhu
01-23-2018, 08:31 AM
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.