More on Format part of a found text string

J

John Smith

I'd like to change all the numbers sandwiched between two
alphabets to subcript.

The code at the end of this article, when applied to "C5H8N2S4Zn",
only changes the digits in C5 and N2 to subscript and leaves H8
and S4 intact.

I monitored rText in the debug mode and found that it was first
"C5H", then "5", then "C". When the code looped back to the first
"Do While", rText became "N2S", not "H8N" as I wanted.

Is there a way to modify the following code so it will first find
"C5H" then "H8N", "N2S", and finally "S4Z"? Thanks.
-----------------------------------------
Sub test()

Dim rtext As Range

With Selection
.HomeKey wdStory

With .Find

Do While .Execute(findText:="[A-z][0-9]{1,}[A-z]", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True

Set rtext = Selection.Range
With rtext.Find
Do While .Execute(findText:="[0-9]{1,}", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=False) = True
rtext.Font.Subscript = True

Exit Do
Loop

End With
rtext.MoveStart Unit:=wdCharacter, Count:=-1
rtext.MoveEnd Unit:=wdCharacter, Count:=-1
Loop
End With

End With
 
M

macropod

Hi John,

Try:
Sub ChemicalSubScripter()
Dim MyRange As Range
With ActiveDocument
Set MyRange = Selection.Range
Selection.GoTo What:=wdGoToPage, Name:="1"
With .Content.Find
.Replacement.ClearFormatting
.Text = "([A-Z][0-9]{1,})"
.ClearFormatting
With .Replacement
.ClearFormatting
.Text = "\1"
End With
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
.Execute
With Selection.Find
.Text = "([0-9]{1,})"
With .Replacement
.Text = "\1"
.Font.Subscript = True
End With
.Execute Replace:=wdReplaceAll
End With
End With
MyRange.Select
End With
Set MyRange = Nothing
End Sub
 
M

macropod

Oops - that's not going to work (it subscripts all numbers, not just the ones in chemical formulations).

--
Cheers
macropod
[MVP - Microsoft Word]


macropod said:
Hi John,

Try:
Sub ChemicalSubScripter()
Dim MyRange As Range
With ActiveDocument
Set MyRange = Selection.Range
Selection.GoTo What:=wdGoToPage, Name:="1"
With .Content.Find
.Replacement.ClearFormatting
.Text = "([A-Z][0-9]{1,})"
.ClearFormatting
With .Replacement
.ClearFormatting
.Text = "\1"
End With
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
.Execute
With Selection.Find
.Text = "([0-9]{1,})"
With .Replacement
.Text = "\1"
.Font.Subscript = True
End With
.Execute Replace:=wdReplaceAll
End With
End With
MyRange.Select
End With
Set MyRange = Nothing
End Sub

--
Cheers
macropod
[MVP - Microsoft Word]


John Smith said:
I'd like to change all the numbers sandwiched between two
alphabets to subcript.

The code at the end of this article, when applied to "C5H8N2S4Zn",
only changes the digits in C5 and N2 to subscript and leaves H8
and S4 intact.

I monitored rText in the debug mode and found that it was first
"C5H", then "5", then "C". When the code looped back to the first
"Do While", rText became "N2S", not "H8N" as I wanted.

Is there a way to modify the following code so it will first find
"C5H" then "H8N", "N2S", and finally "S4Z"? Thanks.
-----------------------------------------
Sub test()

Dim rtext As Range

With Selection
.HomeKey wdStory

With .Find

Do While .Execute(findText:="[A-z][0-9]{1,}[A-z]", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True

Set rtext = Selection.Range
With rtext.Find
Do While .Execute(findText:="[0-9]{1,}", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=False) = True
rtext.Font.Subscript = True

Exit Do
Loop

End With
rtext.MoveStart Unit:=wdCharacter, Count:=-1
rtext.MoveEnd Unit:=wdCharacter, Count:=-1
Loop
End With

End With
 
P

Pesach Shelnitz

The original macro can be fixed to do what was intended by simpling recalling
some basics.

As I'm sure we all know, the Selection object represents the insertion point
or the selected text, while a Range object represents a portion of the doc
defined by a starting position and an ending position, regardless of whether
the text in the range is selected or not. A Range object is convenient for
formatting a part of found text, and in the case under discussion, the start
and end of the range can be set from what we know about the position of the
number to be formatted without performing a second search within the text
found. The Range object should simply be defined as the range extending from
the second character in the text found to the next-to-last character in the
text found. This range includes only the number in the text found.

The other important fact that we must bear in mind here is that, by default,
a repeated search continues from the end of the text found in the previous
search. The original macro finds "C5H" in the first search cycle. In order to
find "H8N" in the second search, the second search must start before the "H"
in the text selected in the first search. This can be achieved by collapsing
the selection and moving the cursor to the position after the number.

The end result is as follows:

Sub test()

Dim rtext As Range

Selection.HomeKey wdStory
With Selection.Find
.ClearFormatting
Do While .Execute(findText:="[A-z][0-9]{1,}[A-z]", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True
Set rtext = ActiveDocument.Range(Start:=Selection.Start + 1, _
End:=Selection.End - 1)
rtext.Font.Subscript = True
Selection.Collapse Direction:=wdCollapseStart
Selection.MoveRight Unit:=wdCharacter, Count:=2
Loop
End With
End Sub

Since this macro is intended to format the numbers in chemical formulas as
subscripts, we might want to continue this discussion and enable the macro to
find two-digit and three-digit numbers.

--
Hope this helps,
Pesach Shelnitz


macropod said:
Oops - that's not going to work (it subscripts all numbers, not just the ones in chemical formulations).

--
Cheers
macropod
[MVP - Microsoft Word]


macropod said:
Hi John,

Try:
Sub ChemicalSubScripter()
Dim MyRange As Range
With ActiveDocument
Set MyRange = Selection.Range
Selection.GoTo What:=wdGoToPage, Name:="1"
With .Content.Find
.Replacement.ClearFormatting
.Text = "([A-Z][0-9]{1,})"
.ClearFormatting
With .Replacement
.ClearFormatting
.Text = "\1"
End With
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
.Execute
With Selection.Find
.Text = "([0-9]{1,})"
With .Replacement
.Text = "\1"
.Font.Subscript = True
End With
.Execute Replace:=wdReplaceAll
End With
End With
MyRange.Select
End With
Set MyRange = Nothing
End Sub

--
Cheers
macropod
[MVP - Microsoft Word]


John Smith said:
I'd like to change all the numbers sandwiched between two
alphabets to subcript.

The code at the end of this article, when applied to "C5H8N2S4Zn",
only changes the digits in C5 and N2 to subscript and leaves H8
and S4 intact.

I monitored rText in the debug mode and found that it was first
"C5H", then "5", then "C". When the code looped back to the first
"Do While", rText became "N2S", not "H8N" as I wanted.

Is there a way to modify the following code so it will first find
"C5H" then "H8N", "N2S", and finally "S4Z"? Thanks.
-----------------------------------------
Sub test()

Dim rtext As Range

With Selection
.HomeKey wdStory

With .Find

Do While .Execute(findText:="[A-z][0-9]{1,}[A-z]", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True

Set rtext = Selection.Range
With rtext.Find
Do While .Execute(findText:="[0-9]{1,}", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=False) = True
rtext.Font.Subscript = True

Exit Do
Loop

End With
rtext.MoveStart Unit:=wdCharacter, Count:=-1
rtext.MoveEnd Unit:=wdCharacter, Count:=-1
Loop
End With

End With
 
M

macropod

Hi ,

Here's a revised version that (I think) does all it should:
Sub ChemicalSubScripter()
Dim MyRange As Range
Selection.HomeKey wdStory
With Selection.Find
.ClearFormatting
.Text = "[A-z][0-9]{1,}"
.MatchWildcards = True
.Wrap = wdFindStop
.Forward = True
Do While .Execute = True
Set MyRange = ActiveDocument.Range(Start:=Selection.Start + 1, End:=Selection.End)
MyRange.Font.Subscript = True
Selection.Collapse Direction:=wdCollapseEnd
Loop
End With
Set MyRange = Nothing
End Sub

As coded, the macro finds numbers with one or more digits following a letter. As well as dealing with chemical compounds like
C5H8N2S4Zn, the code will also handle C5H8N2S4 (which neither the OP's code nor your revision to it do). Handling multi-digit
numbers is as simple as replacing:
Selection.Collapse Direction:=wdCollapseStart
Selection.MoveRight Unit:=wdCharacter, Count:=2
with:
Selection.Collapse Direction:=wdCollapseEnd

--
Cheers
macropod
[MVP - Microsoft Word]


Pesach Shelnitz said:
The original macro can be fixed to do what was intended by simpling recalling
some basics.

As I'm sure we all know, the Selection object represents the insertion point
or the selected text, while a Range object represents a portion of the doc
defined by a starting position and an ending position, regardless of whether
the text in the range is selected or not. A Range object is convenient for
formatting a part of found text, and in the case under discussion, the start
and end of the range can be set from what we know about the position of the
number to be formatted without performing a second search within the text
found. The Range object should simply be defined as the range extending from
the second character in the text found to the next-to-last character in the
text found. This range includes only the number in the text found.

The other important fact that we must bear in mind here is that, by default,
a repeated search continues from the end of the text found in the previous
search. The original macro finds "C5H" in the first search cycle. In order to
find "H8N" in the second search, the second search must start before the "H"
in the text selected in the first search. This can be achieved by collapsing
the selection and moving the cursor to the position after the number.

The end result is as follows:

Sub test()

Dim rtext As Range

Selection.HomeKey wdStory
With Selection.Find
.ClearFormatting
Do While .Execute(findText:="[A-z][0-9]{1,}[A-z]", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True
Set rtext = ActiveDocument.Range(Start:=Selection.Start + 1, _
End:=Selection.End - 1)
rtext.Font.Subscript = True
Selection.Collapse Direction:=wdCollapseStart
Selection.MoveRight Unit:=wdCharacter, Count:=2
Loop
End With
End Sub

Since this macro is intended to format the numbers in chemical formulas as
subscripts, we might want to continue this discussion and enable the macro to
find two-digit and three-digit numbers.

--
Hope this helps,
Pesach Shelnitz


macropod said:
Oops - that's not going to work (it subscripts all numbers, not just the ones in chemical formulations).

--
Cheers
macropod
[MVP - Microsoft Word]


macropod said:
Hi John,

Try:
Sub ChemicalSubScripter()
Dim MyRange As Range
With ActiveDocument
Set MyRange = Selection.Range
Selection.GoTo What:=wdGoToPage, Name:="1"
With .Content.Find
.Replacement.ClearFormatting
.Text = "([A-Z][0-9]{1,})"
.ClearFormatting
With .Replacement
.ClearFormatting
.Text = "\1"
End With
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
.Execute
With Selection.Find
.Text = "([0-9]{1,})"
With .Replacement
.Text = "\1"
.Font.Subscript = True
End With
.Execute Replace:=wdReplaceAll
End With
End With
MyRange.Select
End With
Set MyRange = Nothing
End Sub

--
Cheers
macropod
[MVP - Microsoft Word]


I'd like to change all the numbers sandwiched between two
alphabets to subcript.

The code at the end of this article, when applied to "C5H8N2S4Zn",
only changes the digits in C5 and N2 to subscript and leaves H8
and S4 intact.

I monitored rText in the debug mode and found that it was first
"C5H", then "5", then "C". When the code looped back to the first
"Do While", rText became "N2S", not "H8N" as I wanted.

Is there a way to modify the following code so it will first find
"C5H" then "H8N", "N2S", and finally "S4Z"? Thanks.
-----------------------------------------
Sub test()

Dim rtext As Range

With Selection
.HomeKey wdStory

With .Find

Do While .Execute(findText:="[A-z][0-9]{1,}[A-z]", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True

Set rtext = Selection.Range
With rtext.Find
Do While .Execute(findText:="[0-9]{1,}", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=False) = True
rtext.Font.Subscript = True

Exit Do
Loop

End With
rtext.MoveStart Unit:=wdCharacter, Count:=-1
rtext.MoveEnd Unit:=wdCharacter, Count:=-1
Loop
End With

End With
 
J

John Smith

I had read it before posting. I'm afraid your solution is not
general enough. If I understand your code correctly, your code
cannot handle more than one digit. It will have problem for
formulas like C102H206F15O33N11 etc.

Graham said:
Investigate - 'Format part of a found text string in a list of items' at
http://www.gmayor.com/word_vba_examples.htm
-- <>>< ><<> ><<> <>>< ><<> <>>< <>><<> Graham Mayor - Word MVP My
web site www.gmayor.com
I'd like to change all the numbers sandwiched between two
alphabets to subcript.

The code at the end of this article, when applied to "C5H8N2S4Zn",
only changes the digits in C5 and N2 to subscript and leaves H8
and S4 intact.

I monitored rText in the debug mode and found that it was first
"C5H", then "5", then "C". When the code looped back to the first
"Do While", rText became "N2S", not "H8N" as I wanted.

Is there a way to modify the following code so it will first find
"C5H" then "H8N", "N2S", and finally "S4Z"? Thanks.
-----------------------------------------
Sub test()

Dim rtext As Range

With Selection
.HomeKey wdStory

With .Find

Do While .Execute(findText:="[A-z][0-9]{1,}[A-z]", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True

Set rtext = Selection.Range
With rtext.Find
Do While .Execute(findText:="[0-9]{1,}", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=False) = True
rtext.Font.Subscript = True

Exit Do
Loop

End With
rtext.MoveStart Unit:=wdCharacter, Count:=-1
rtext.MoveEnd Unit:=wdCharacter, Count:=-1
Loop
End With

End With
 
G

Graham Mayor

The particular item I referred you to can be adapted to any chemical
formula, as it identifies the individual characters from the found string to
be formatted by their position in the found text string. You could use it to
format each character individually if you wished. It is not a generic
wildcard search tool, but addresses a list of identified text strings.

--
<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
Graham Mayor - Word MVP


<>>< ><<> ><<> <>>< ><<> <>>< <>><<>


John said:
I had read it before posting. I'm afraid your solution is not
general enough. If I understand your code correctly, your code
cannot handle more than one digit. It will have problem for
formulas like C102H206F15O33N11 etc.

Graham said:
Investigate - 'Format part of a found text string in a list of
items' at http://www.gmayor.com/word_vba_examples.htm
-- <>>< ><<> ><<> <>>< ><<> <>>< <>><<> Graham Mayor - Word MVP My
web site www.gmayor.com
I'd like to change all the numbers sandwiched between two
alphabets to subcript.

The code at the end of this article, when applied to "C5H8N2S4Zn",
only changes the digits in C5 and N2 to subscript and leaves H8
and S4 intact.

I monitored rText in the debug mode and found that it was first
"C5H", then "5", then "C". When the code looped back to the first
"Do While", rText became "N2S", not "H8N" as I wanted.

Is there a way to modify the following code so it will first find
"C5H" then "H8N", "N2S", and finally "S4Z"? Thanks.
-----------------------------------------
Sub test()

Dim rtext As Range

With Selection
.HomeKey wdStory

With .Find

Do While .Execute(findText:="[A-z][0-9]{1,}[A-z]", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True

Set rtext = Selection.Range
With rtext.Find
Do While .Execute(findText:="[0-9]{1,}", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=False) = True
rtext.Font.Subscript = True

Exit Do
Loop

End With
rtext.MoveStart Unit:=wdCharacter, Count:=-1
rtext.MoveEnd Unit:=wdCharacter, Count:=-1
Loop
End With

End With
 
J

John Smith

Thanks. This macro does exactly what I wanted it to do. And it
handles more than one digit. I tested up to five digit numbers and
the macro worked fine.

I was using a clumsy four step macro to do the subscript. With
some modification of this macro, it can be done in one step.
 
J

John Smith

Thanks. This macro does more than what I want. In fact, it handles
about 85% of all the chemical formulas. The only thing it doesn't
handle is the number after ")". I was using a clumsy four step
macro to do the subscript. By simply changing the [A-z] part in
the findText to [A-z\)], one step is enough. Thanks.
 
P

Pesach Shelnitz

Now I understand your requirements a little better. Since the goal is to
format all numbers that are subscripts in chemical formulas as subscripts,
the close parentheses character ")" should be added to the list of characters
that may appear before a number, and the criterion that only numbers that are
followed by a letter will be found should be removed. This way, the macro
will also process the number in CO2. Also, since numbers of any length should
be found, the cursor should be placed after the last digit found when the
macro completes.

The result of these changes is as follows.

Sub ChemSubscript()

Dim rtext As Range

Selection.HomeKey wdStory
With Selection.Find
.ClearFormatting
Do While .Execute(findText:="[A-z)][0-9]{1,}", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True
Set rtext = ActiveDocument.Range(Start:=Selection.Start + 1, _
End:=Selection.End)
rtext.Font.Subscript = True
Selection.Collapse Direction:=wdCollapseEnd
Loop
End With
End Sub

If you find my posts helpful, please rate them by responding to question at
the bottom of the post. Thanks.

--
Hope this helps,
Pesach Shelnitz


John Smith said:
Thanks. This macro does exactly what I wanted it to do. And it
handles more than one digit. I tested up to five digit numbers and
the macro worked fine.

I was using a clumsy four step macro to do the subscript. With
some modification of this macro, it can be done in one step.

Pesach said:
The original macro can be fixed to do what was intended by simpling recalling
some basics.

As I'm sure we all know, the Selection object represents the insertion point
or the selected text, while a Range object represents a portion of the doc
defined by a starting position and an ending position, regardless of whether
the text in the range is selected or not. A Range object is convenient for
formatting a part of found text, and in the case under discussion, the start
and end of the range can be set from what we know about the position of the
number to be formatted without performing a second search within the text
found. The Range object should simply be defined as the range extending from
the second character in the text found to the next-to-last character in the
text found. This range includes only the number in the text found.

The other important fact that we must bear in mind here is that, by default,
a repeated search continues from the end of the text found in the previous
search. The original macro finds "C5H" in the first search cycle. In order to
find "H8N" in the second search, the second search must start before the "H"
in the text selected in the first search. This can be achieved by collapsing
the selection and moving the cursor to the position after the number.

The end result is as follows:

Sub test()

Dim rtext As Range

Selection.HomeKey wdStory
With Selection.Find
.ClearFormatting
Do While .Execute(findText:="[A-z][0-9]{1,}[A-z]", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True
Set rtext = ActiveDocument.Range(Start:=Selection.Start + 1, _
End:=Selection.End - 1)
rtext.Font.Subscript = True
Selection.Collapse Direction:=wdCollapseStart
Selection.MoveRight Unit:=wdCharacter, Count:=2
Loop
End With
End Sub

Since this macro is intended to format the numbers in chemical formulas as
subscripts, we might want to continue this discussion and enable the macro to
find two-digit and three-digit numbers.
 
M

macropod

Hi Pesach,

A potentially significant issue with your 'A-z' find string is that it will also find and process numbers following characters in
the '[\]^_`' range. Thus, you need 'A-Za-z' instead.

--
Cheers
macropod
[Microsoft MVP - Word]


Pesach Shelnitz said:
Now I understand your requirements a little better. Since the goal is to
format all numbers that are subscripts in chemical formulas as subscripts,
the close parentheses character ")" should be added to the list of characters
that may appear before a number, and the criterion that only numbers that are
followed by a letter will be found should be removed. This way, the macro
will also process the number in CO2. Also, since numbers of any length should
be found, the cursor should be placed after the last digit found when the
macro completes.

The result of these changes is as follows.

Sub ChemSubscript()

Dim rtext As Range

Selection.HomeKey wdStory
With Selection.Find
.ClearFormatting
Do While .Execute(findText:="[A-z)][0-9]{1,}", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True
Set rtext = ActiveDocument.Range(Start:=Selection.Start + 1, _
End:=Selection.End)
rtext.Font.Subscript = True
Selection.Collapse Direction:=wdCollapseEnd
Loop
End With
End Sub

If you find my posts helpful, please rate them by responding to question at
the bottom of the post. Thanks.

--
Hope this helps,
Pesach Shelnitz


John Smith said:
Thanks. This macro does exactly what I wanted it to do. And it
handles more than one digit. I tested up to five digit numbers and
the macro worked fine.

I was using a clumsy four step macro to do the subscript. With
some modification of this macro, it can be done in one step.

Pesach said:
The original macro can be fixed to do what was intended by simpling recalling
some basics.

As I'm sure we all know, the Selection object represents the insertion point
or the selected text, while a Range object represents a portion of the doc
defined by a starting position and an ending position, regardless of whether
the text in the range is selected or not. A Range object is convenient for
formatting a part of found text, and in the case under discussion, the start
and end of the range can be set from what we know about the position of the
number to be formatted without performing a second search within the text
found. The Range object should simply be defined as the range extending from
the second character in the text found to the next-to-last character in the
text found. This range includes only the number in the text found.

The other important fact that we must bear in mind here is that, by default,
a repeated search continues from the end of the text found in the previous
search. The original macro finds "C5H" in the first search cycle. In order to
find "H8N" in the second search, the second search must start before the "H"
in the text selected in the first search. This can be achieved by collapsing
the selection and moving the cursor to the position after the number.

The end result is as follows:

Sub test()

Dim rtext As Range

Selection.HomeKey wdStory
With Selection.Find
.ClearFormatting
Do While .Execute(findText:="[A-z][0-9]{1,}[A-z]", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True
Set rtext = ActiveDocument.Range(Start:=Selection.Start + 1, _
End:=Selection.End - 1)
rtext.Font.Subscript = True
Selection.Collapse Direction:=wdCollapseStart
Selection.MoveRight Unit:=wdCharacter, Count:=2
Loop
End With
End Sub

Since this macro is intended to format the numbers in chemical formulas as
subscripts, we might want to continue this discussion and enable the macro to
find two-digit and three-digit numbers.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top