Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Selecting and manipulating a range of text using a macro

Status
Not open for further replies.

Icarus050

ISP
May 15, 2007
12
AU
I have a document with sections defined by a line of text with a # at the start.

So:

# Fri 11 May Subject: Formatting Test
This is a test of automatically formatting the extracted text
and more testing..

# Sat 12 May Subject: Still formatting text
This is the second section.
Still the second section

# Sun 13 May Subject: 3rd section
Blah blah
Blah blah blah..


What I need is a macro which will find, and then put a border around the seperate sections (dictated by the #)..

Any help would be great..

Cheers,
Ic.
 
This is what the macro recorder gave me, extended by a loop:
Code:
Sub BorderAllRanges()
Dim startr as Long, endr as Long
With Selection.Find
    .ClearFormatting
    .Replacement.ClearFormatting
    .Text = "#"
    .Replacement.Text = ""
    .MatchWildcards = False
    .Format = False
    .Wrap = wdFindStop
    .Forward = True
    .Execute
End With

Do While Selection.Find.Found
   startr=Selection.Start
   Selection.Collapse wdCollapseEnd
   Selection.Find.Execute
   endr=Selection.Start-1
   Selection.Start=startr
   Selection.End=endr

   ApplyBorder

   Selection.Collapse wdCollapseEnd
   Selection.Find.Execute
Loop

End Sub

Sub applyBorder()
With Selection.ParagraphFormat
        With .Borders(wdBorderLeft)
            .LineStyle = wdLineStyleSingle
            .LineWidth = wdLineWidth050pt
            .Color = wdColorAutomatic
        End With
        With .Borders(wdBorderRight)
            .LineStyle = wdLineStyleSingle
            .LineWidth = wdLineWidth050pt
            .Color = wdColorAutomatic
        End With
        With .Borders(wdBorderTop)
            .LineStyle = wdLineStyleSingle
            .LineWidth = wdLineWidth050pt
            .Color = wdColorAutomatic
        End With
        With .Borders(wdBorderBottom)
            .LineStyle = wdLineStyleSingle
            .LineWidth = wdLineWidth050pt
            .Color = wdColorAutomatic
        End With
        With .Borders
            .DistanceFromTop = 1
            .DistanceFromLeft = 4
            .DistanceFromBottom = 1
            .DistanceFromRight = 4
            .Shadow = False
        End With
    End With
    With Options
        .DefaultBorderLineStyle = wdLineStyleSingle
        .DefaultBorderLineWidth = wdLineWidth050pt
        .DefaultBorderColor = wdColorAutomatic
    End With
End Sub

That should do the trick.
:)

Cheers,
MiS

[blue]Help us, join us, participate
IAHRA - International Alliance of Human Rights Advocates[/blue]
 
Thanks for the quick response..

Hmm, it found one group of text (the last in the document if that helps with troubleshooting) but then it went into a loop till it used up all 2gb of my RAM.. which is impressive, but not exactly what I was after :)

Any ideas?
 
:d'uh:

Yeah, I know why:
The routine seeks one "#" and then the next to determine the end of block one.

Two possibilities:
a) Change the respective part of the code to this (bolded addition
Code:
Do While Selection.Find.Found
   startr=Selection.Start
   Selection.Collapse wdCollapseEnd
   Selection.Find.Execute
   [b]if not selection.find.found then exit do[/b]
   endr=Selection.Start-1

or better yet the loop to this:
Code:
Do While Selection.Find.Found
   startr=Selection.Start
[b]   Selection.moveleft unit:=wdparagraph, extend:=wdextend[/b]

   ApplyBorder

   Selection.Collapse wdCollapseEnd
   Selection.Find.Execute
Loop

[blue]Help us, join us, participate
IAHRA - International Alliance of Human Rights Advocates[/blue]
 
Alright, closer to the right result, option a) skips the first group of text, but then puts one border around all the rest of the groups.

Option b) gives me a runtime error of '4120' Bad Perameter on 'Selection.moveleft unit:=wdparagraph, extend:=wdextend'
 
Ohhh so close..

That puts a border around just the line starting with the #, which, looking at the end result isn't bad at all, but if you've got a lightning fast fix for that too, I'm all ears :)
 
Using Selection is generally a not good way of processing. It is better to use Range.

The following may, or may not, work properly.

1. It depends on what you happening qwith your document. If you are using Styles, and NOT using "extra' paragraph marks to make space between paragraphs, this will have to be adjusted.

2. Bordered paragraphs that touch (are contiguous) will merge borders. This adds a NON-bordered paragraph between the bordered ones.

Here is the starting text. The <p> indicates a paragraph mark. I am also using TGML format to indicate the whole "chunks". Chunk 1 is italics, Chunk is plain, Chunk 3 is bold.


# Fri 11 May Subject: Formatting Test<p>
This is a test of automatically formatting the extracted text<p>
and more testing.<p>
<p>
This is a test of automatically formatting the extracted text<p>
and more testing.<p>
<p>

# Sat 12 May Subject: Still formatting text<p>
This is the second section.<p>
Still the second section<p>
This is the second section.<p>
Still the second section<p>
<p>
# Sun 13 May Subject: 3rd section<p>
Blah blah<p>
Blah blah blah.<p>


The code will put a border around each "chunk", adding a separator paragraph in order to stop the borders from merging.
Code:
Sub FindChunks()
Dim r As Range
Dim CsetReturn As Long
Set r = ActiveDocument.Range(Start:=0, End:=0)
Do Until r.End = ActiveDocument.Range.End
   With r
      CsetReturn = _
           (.MoveEndUntil(Cset:="#", Count:=wdForward))
      If CsetReturn >= 1 Then
        .Collapse Direction:=wdCollapseEnd
        .MoveEnd unit:=wdCharacter, Count:=1
        CsetReturn = _
           (.MoveEndUntil(Cset:="#", Count:=wdForward))
        If CsetReturn >= 1 Then
           Call ApplyBorders(r)
           .Collapse Direction:=wdCollapseEnd
           .InsertParagraphAfter
        Else
           .End = ActiveDocument.Range.End
           Call ApplyBorders(r)
        End If
      Else
         .MoveStart unit:=wdCharacter, Count:=1
         .End = ActiveDocument.Range.End
         Call ApplyBorders(r)
      End If
   End With
Loop
End Sub

Sub ApplyBorders(r As Range)
Dim var
   With r.ParagraphFormat
      For var = -4 To -1
         With .Borders(var)
           .LineStyle = wdLineStyleSingle
           .LineWidth = wdLineWidth050pt
           .Color = wdColorAutomatic
         End With
      Next
   End With
End Sub

Note the change to ApplyBorders. In the recorded macro there are all those With...End With instructions for each of the borders. wdBorderTop, wdBorderLeft, wdBorderRght, dBorderBottom

In this case, each range is passed to ApplyBorders as a parameter, and the format is applied to it.

This is one of the things with recorded macros. They often add huge amounts of clutter. By using the numeric values of wdBorderTop etc. you can process them all in a simple loop.

Essentially what is happening is a range object is created at the start of the document. It moves the End until it finds a "#". It collapses, moves forward to include the "#", then moves forward to find the next "#".

If it finds one - CsetReturn = 1 or greater - it applys the border.

If it does not - it makes the Range from the currently found "#", to the end of the document. Then applies the border.

Of course this most likely may have to be adjusted, as that final assuption could be incorrect. It was not stated if the last "#" does indeed include up to the end of the document.

No Selection is made.

Gerry
My paintings and sculpture
 
Ahh, you guys rock!

MakeItSo, thanks so much for your help..

fumei that worked first time, you have no idea how much time that is going to save me.

Cheers.
Ic.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top