PDA

View Full Version : [SOLVED:] Replace specific characters in a selection



Jennifer
02-11-2017, 02:55 PM
I am having a little trouble writing a macro that will replace specific individual characters in a selection with corresponding characters from another string. For example, if I wanted to replace all occurrences of the first 5 letters with the next letter in the alphabet ('a' -> 'b', 'b' -> 'c', 'c' -> 'd', etc.), I might define


Alphabet1 = "ABCDEabcde"
Alphabet2 = "BCDEFbcdef"

Then I need some code to step through the selection character by character, look it up in Alphabet1, and, if it is found, replace it with the corresponding character in Alphabet2.

Here's what I have so far. It works for 1 iteration, but on the second iteration, the Selection.Characters statement gets a run-time 5941 error. If I comment it out, as shown below, the rest of the loop works correctly.

I suspect that that statement is somehow changing the selection to just the first character, but I don't know what to do about it.


Dim String1 As String 'The original text
Dim StrNdx As Long 'The loop index
Dim CharNdx As Long 'The character index in Alphabet1
Dim NextChar1 As String 'The next character from the source string
Dim NextChar2 As String 'The replacement character from Alphabet2

String1 = Selection.Range 'Get the source string

For StrNdx = 1 To Len(String1) 'Loop through the source characters
NextChar1 = Mid(String1, StrNdx, 1) 'Get the next source character
CharNdx = InStr(Alphabet1, NextChar1) 'Get its index in Alphabet1
If CharNdx > 0 Then 'If it's in the alphabet,
NextChar2 = Mid(Alphabet2, CharNdx, 1) 'Get coded character
MsgBox "Replace (" & NextChar1 & ") with (" & NextChar2 & ")"
' Selection.Characters(StrNdx).Text = NextChar2 'Store it in the document
End If 'Otherwise, leave it alone (skip it)
Next StrNdx

gmaxey
02-11-2017, 05:40 PM
It is not clear to me what you are trying to do. Maybe:


Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Const Alphabet1 As String = "ABCDEabcde"
Const Alphabet2 As String = "BCDEFbcdef"
Dim strSel As String
Dim lngIndex As Long
Dim CharNdx As Long 'The character index in Alphabet1
Dim strChr As String 'The next character from the source string
Dim strChrRplc As String 'The replacement character from Alphabet2
Dim oRng As Range
Set oRng = Selection.Range.Duplicate
strSel = Selection.Range.Text 'Get the source string
For lngIndex = 1 To Len(strSel) 'Loop through the source characters
strChr = Mid(strSel, lngIndex, 1)
CharNdx = InStr(Alphabet1, strChr) 'Get its index in Alphabet1
If CharNdx > 0 Then
strChrRplc = Mid(Alphabet2, CharNdx, 1) 'Get coded character
oRng.Characters(lngIndex) = strChrRplc
MsgBox "Replace (" & strChr & ") with (" & strChrRplc & ")"
End If
Next lngIndex
lbl_Exit:
Exit Sub
End Sub

Jennifer
02-12-2017, 01:26 AM
It is not clear to me what you are trying to do.
I'm trying to write a little macro that will encrypt letters to my grandkids with a simple replacement code that they might have fun trying to decode.

What does this instruction do, especially the .Duplicate?

Set oRng = Selection.Range.Duplicate

I came up with something similar, but instead of


oRng.Characters(lngIndex) = strChrRplc

I had


Selection.Characters(lngIndex).Text = strChrRplc

What's the difference? Mine seemed to reset the selection so that the subscript was out of range. Yours doesn't seem to do that. Is that because of the .Duplicate parameter?

PS: What the heck is this "mark007" comment?

gmaxey
02-12-2017, 01:56 AM
Well in this case you don't' really need .duplicate. This works just as well:


Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Const Alphabet1 As String = "ABCDEabcde"
Const Alphabet2 As String = "BCDEFbcdef"
Dim strSel As String
Dim lngIndex As Long
Dim CharNdx As Long 'The character index in Alphabet1
Dim strChr As String 'The next character from the source string
Dim strChrRplc As String 'The replacement character from Alphabet2
Dim oRng As Range
Set oRng = Selection.Range
strSel = Selection.Range.Text 'Get the source string
For lngIndex = 1 To Len(strSel) 'Loop through the source characters
strChr = Mid(strSel, lngIndex, 1)
CharNdx = InStr(Alphabet1, strChr) 'Get its index in Alphabet1
If CharNdx > 0 Then
strChrRplc = Mid(Alphabet2, CharNdx, 1) 'Get coded character
oRng.Characters(lngIndex) = strChrRplc
MsgBox "Replace (" & strChr & ") with (" & strChrRplc & ")"
End If
Next lngIndex
lbl_Exit:
Exit Sub
End Sub


Yours falls over because you destroy the selection as soon as you use Selection.Characters(lngIndex).Text

Select some text and step through this:


Sub ScratchMacro()
'A basic Word macro coded by Greg Maxey
Dim lngIndex As Long
Dim oRng As Range
Set oRng = Selection.Range
For lngIndex = 1 To Selection.Characters.Count
On Error GoTo Err_Handler
Selection.Characters(lngIndex).Text = "A"
Err_ReEntry:
Next
lbl_Exit:
Exit Sub
Err_Handler:
Debug.Print Err.Number & " " & Err.Description
oRng.Characters(lngIndex) = "A"
Resume Err_ReEntry
End Sub


I suppose Mark is the fellow that created the code tags.

Jennifer
02-12-2017, 08:26 AM
Well in this case you don't' really need .duplicate.
OK, but what does .duplicate do?


Yours falls over because you destroy the selection as soon as you use Selection.Characters(lngIndex).Text

Why does mine reset the selection and yours does not? What is different about how the two instructions work?

Thanks

gmaxey
02-12-2017, 08:42 AM
Well the documentation says this:



Word Developer Reference



Range.Duplicate Property


Returns a read-only Range object that represents all the properties of the specified range.Syntax
expression.Duplicate
expression Required. A variable that represents a Range (http://www.vbaexpress.com/forum/HV10329911.htm) object.

Remarks
By duplicating a Range object, you can change the starting or ending character position of the duplicate range without changing the original range.
© 2010 Microsoft Corporation. All rights reserved. (http://www.vbaexpress.com/forum/HV10323630.htm)

Here is a practical example of how I use it. In a new blank document, type about ten X's e.g., *********X. Then select the first 5. Run this code.


Sub ScratchMacroI()
'A basic Word macro coded by Greg Maxey
Dim oRng As Word.Range
Set oRng = Selection.Range
With oRng.Find
.Text = "X"
While .Execute
oRng.Text = "Y"
oRng.Collapse wdCollapseEnd
Wend
End With
lbl_Exit:
Exit Sub
End Sub

The goal is to replace the 5 Xs selected with Ys. That is not the outcome. Repeat using this code:


Sub ScratchMacroII()
'A basic Word macro coded by Greg Maxey
Dim oRng As Word.Range, oRngChk As Range
Set oRng = Selection.Range
Set oRngChk = oRng.Duplicate
With oRng.Find
.Text = "X"
Do While .Execute
If oRng.InRange(oRngChk) Then
oRng.Text = "Y"
oRng.Collapse wdCollapseEnd
Else
Exit Do
End If
Loop
End With
lbl_Exit:
Exit Sub
End Sub



Your version falls over as I explained in my last post.

Jennifer
02-12-2017, 09:22 AM
Well the documentation says this:
What is the Developer Reference? Is it a hard copy book or is it online where I can access it?

I found these online:



https://msdn.microsoft.com/en-us/library/office/gg264383(v=office.15).aspx Office 2013 and later
https://msdn.microsoft.com/en-us/library/office/gg264383(v=office.14).aspx Office 2010 (not maintained)


I found these on Amazon:



https://www.amazon.com/dp/0782129781/ VBA Developers Handbook, 2nd Edition (Getz)
https://www.amazon.com/dp/1565923588/ VB & VBA in a Nutshell: Language (O'Reilly)
https://www.amazon.com/dp/0470634006/ Mastering VBA for Office 2010 (Richard Mansfield)



Here is a practical example of how I use it. In a new blank document, type about ten X's e.g., *********X. Then select the first 5. Run this code.
I'll play around with this. Thanks.

gmaxey
02-12-2017, 09:37 AM
Select the "Duplicate" (or whatever you want information on) and press F1