PDA

View Full Version : Solved: Split document with new filename being first line of new document



PatriciaD
09-27-2010, 08:48 AM
I am SO sorry to be posting. I have seen that there are other posts similar to mine already on here, but I just don't understand the VBA code well enough to adapt it quickly to my situation. My question is similar to Gentle and Philkp, but with differences, obviously.

I am designing recipe cards. some of my documents are over 10 pages long, with each page being a different recipe. (some recipes are 2 pages long). I want to split the document so that each recipe is its own document and that the filename is the name of the recipe, which is the first line of the document. It is NOT a header, just a bold/larger font size than the other parts of the document.

I liked Graham Skan's macro, but it is supposed to be for single pages only. On rare occasions, mine will be two pages. Also, his numbers each new document according to the original page number. I am putting his macro below with what I believe I need to change in green highlight.

I do have hard page breaks for the separation between recipes. As I said I just want the first line of the new document to be the file name. I have attached a .docx file as an example.

Thank you in advance for your help!
Patricia



Sub SplitIntoPages()
Dim docMultiple As Document
Dim docSingle As Document
Dim rngPage As Range
Dim iCurrentPage As Integer
Dim iPageCount As Integer
Dim strNewFileName As String

Application.ScreenUpdating = False 'Makes the code run faster and reduces screen _
flicker a bit.
Set docMultiple = ActiveDocument 'Work on the active document _
(the one currently containing the Selection)
Set rngPage = docMultiple.Range 'instantiate the range object
iCurrentPage = 1
'get the document's page count
iPageCount = docMultiple.Content.ComputeStatistics(wdStatisticPages)
Do Until iCurrentPage > iPageCount
If iCurrentPage = iPageCount Then
rngPage.End = ActiveDocument.Range.End 'last page (there won't be a next page)
Else
'Find the beginning of the next page
'Must use the Selection object. The Range.Goto method will not work on a page
Selection.GoTo wdGoToPage, wdGoToAbsolute, iCurrentPage + 1
'Set the end of the range to the point between the pages
rngPage.End = Selection.Start
End If
rngPage.Copy 'copy the page into the Windows clipboard
Set docSingle = Documents.Add 'create a new document
docSingle.Range.Paste 'paste the clipboard contents to the new document
'remove any manual page break to prevent a second blank
docSingle.Range.Find.Execute Findtext:="^m", ReplaceWith:=""
'build a new sequentially-numbered file name based on the original multi-paged file name and path
strNewFileName = Replace(docMultiple.FullName, ".docx", "_" & Right$("000" & iCurrentPage, 4) & ".docx")
docSingle.SaveAs strNewFileName 'save the new single-paged document
iCurrentPage = iCurrentPage + 1 'move to the next page
docSingle.Close 'close the new document
rngPage.Collapse wdCollapseEnd 'go to the next page
Loop 'go to the top of the do loop
Application.ScreenUpdating = True 'restore the screen updating

'Destroy the objects.
Set docMultiple = Nothing
Set docSingle = Nothing
Set rngPage = Nothing
End Sub

fumei
09-27-2010, 10:01 AM
So what exactly is your problem? Just getting the filename to be the first line?

If so, then the string to be used for the filename is simply the string text of the first paragraph (and assuming you still want to use the same path.folder as your original document:
strNewFileName = docMultiple.Path & "\" & _
Left(docSingle.Range.Paragraphs(1), Len(docSingle.Range.Paragraphs(1) -1))

It looks more complicated than it is.

Left(docSingle.Range.Paragraphs(1), Len(docSingle.Range.Paragraphs(1) -1))

Paragraph(1) will include the paragraph mark, and you do NOT want to do that, as it will cause a filename error.

So, for example: Baked Brie with Sundried Tomatoes^p

^p is the symbol for a paragraph mark.


The syntax for Left is: Left(the_string, how_many_characters) - starting from....the left.

So....
So use LEFT(the paragraph, LENGTH of the paragraph - 1)

Baked Brie with Sundried Tomatoes^p

becomes - ta-da - Baked Brie with Sundried Tomatoes

so
strNewFileName = docMultiple.Path & "\" & _
Left(docSingle.Range.Paragraphs(1), Len(docSingle.Range.Paragraphs(1) -1))
means...

the path/folder of docMultiple, plus a folder slash (IMPORTANT!), plus the text of the first paragraph less the terminating paragraph mark.

PatriciaD
09-27-2010, 11:58 AM
Thank you, Gerry, for responding!
I am a little dense so please bear with me.




so
strNewFileName = docMultiple.Path & "\" & _
Left(docSingle.Range.Paragraphs(1), Len(docSingle.Range.Paragraphs(1) -1))
means...

the path/folder of docMultiple, plus a folder slash (IMPORTANT!), plus the text of the first paragraph less the terminating paragraph mark.
I have it exactly as you have written it but it does not like the 2nd .paragraphs in the string.

Do I need to add some sort of info to the top of the page? Or should it already know what Paragraphs means?

I have been playing around with different solutions, but I haven't hit on the right one yet.

Thank you for your time.

fumei
09-27-2010, 12:25 PM
Oooops. Try using Paragraphs(1).Range.Text. Len needs text, and .Paragraphs(1) is, technically a range, not a string. As this is getting a bit long, work it in steps.
Dim strWorking As String
' this puts in the path and folder string
strNewFileName = docMultiple.Path & "\"

' give the variable Working the paragraph text (string)
strWorking = docSingle.Range.Paragraphs(1).Range.Text

' NOW we can use it fully
strNewFileName = strNewFileName & Left(strWorking, Len(strWorking -1))


You can, of course, not use that secondary string variable (strWorking), in which case, it would be:

strNewFileName = strNewFileName & Left(docSingle.Range.Paragraphs(1), _
Len(docSingle.Range.Paragraphs(1).Range.Text -1))
I just added the strWorking to make it less intimidating looking.

This demonstrates a little bit of VBA fussiness.

MsgBox ActiveDocument.Range.Paragraphs(1)
displays the text of Paragraph(1)...or so it seems.

However,
Msgbox Len(ActiveDocument.Range.Paragraphs(1))
will fail, as Len requires a string..and again technically speaking ActiveDocument.Range.Paragraphs(1) is NOT a string. This also demonstrates the result of using the default property of objects.

So, again;
Msgbox Len(ActiveDocument.Range.Paragraphs(1))
will fail, but...


Msgbox Len(ActiveDocument.Range.Paragraphs(1).Range.Text)
will not fail, as Len returns the Length of the explicit string - .Text.

PatriciaD
09-27-2010, 12:26 PM
I forgot to tell you the rest of the compile error:type mismatch.

fumei
09-27-2010, 12:30 PM
Post your code.

PatriciaD
09-27-2010, 01:55 PM
delete double post

PatriciaD
09-27-2010, 02:07 PM
Sorry, we were typing at the same time on that one, the compile error you addressed above is what that other post of mine was. You took care of that, but now Len is having conniptions over -1. I tried both ways listed and they both gave me the same error.

my new error is compile error: variable required - can't assign to this expression

and it highlights the -1. Should text be another word so it allows for reading negative numbers?

strNewFileName = strNewFileName & Left(strWorking, Len(strWorking - 1))

and

strNewFileName = docMultiple.Path & "\" & _
Left(docSingle.Range.Paragraphs(1), Len(docSingle.Range.Paragraphs(1).Range.Text - 1))


I am reposting the whole code just in case you need it again. Thanks again for your patience and help.

Sub SplitIntoPages()
Dim docMultiple As Document
Dim docSingle As Document
Dim rngPage As Range
Dim iCurrentPage As Integer
Dim iPageCount As Integer
Dim strNewFileName As String
strNewFileName = docMultiple.Path & "\"

Application.ScreenUpdating = False 'Makes the code run faster and reduces screen _
flicker a bit.
Set docMultiple = ActiveDocument 'Work on the active document _
(the one currently containing the Selection)
Set rngPage = docMultiple.Range 'instantiate the range object

iCurrentPage = 1
'get the document's page count
iPageCount = docMultiple.Content.ComputeStatistics(wdStatisticPages)
Do Until iCurrentPage > iPageCount
If iCurrentPage = iPageCount Then
rngPage.End = ActiveDocument.Range.End 'last page (there won't be a next page)
Else
'Find the beginning of the next page
'Must use the Selection object. The Range.Goto method will not work on a page
Selection.GoTo wdGoToPage, wdGoToAbsolute, iCurrentPage + 1
'Set the end of the range to the point between the pages
rngPage.End = Selection.Start
End If
rngPage.Copy 'copy the page into the Windows clipboard
Set docSingle = Documents.Add 'create a new document
docSingle.Range.Paste 'paste the clipboard contents to the new document
'remove any manual page break to prevent a second blank
docSingle.Range.Find.Execute Findtext:="^m", ReplaceWith:=""
'build a new sequentially-numbered file name based on the original multi-paged file name and path
strNewFileName = strNewFileName & Left(docSingle.Range.Paragraphs(1), Len(docSingle.Range.Paragraphs(1).Range.Text - 1))
docSingle.SaveAs strNewFileName 'save the new single-paged document
iCurrentPage = iCurrentPage + 1 'move to the next page
docSingle.Close 'close the new document
rngPage.Collapse wdCollapseEnd 'go to the next page
Loop 'go to the top of the do loop
Application.ScreenUpdating = True 'restore the screen updating

'Destroy the objects.
Set docMultiple = Nothing
Set docSingle = Nothing
Set rngPage = Nothing
End Sub

fumei
09-28-2010, 02:18 PM
It should be:

strNewFileName = strNewFileName & Left(docSingle.Range.Paragraphs(1), _
Len(docSingle.Range.Paragraphs(1).Range.Text) - 1)

NOT:

strNewFileName = strNewFileName & Left(docSingle.Range.Paragraphs(1), _
Len(docSingle.Range.Paragraphs(1).Range.Text - 1))


Note the placement of brackets. Len is a function and needs to be fully closed.

PatriciaD
09-29-2010, 06:18 AM
Thank you, Gerry!

It works and you have made my life easier. I still don't understand some of the commands, but I am trying to get it. Could you recommend something for the layperson to learn this? I have done the basic stuff on line (tutorials), but they are pretty simple and straight forward. I need a little more meat, but not too much LOL. It might mean taking a class. If that is the case, what kind of class would you recommend...I have not seen a class (college level) that is called "Macros". Would I look for VBA or C++ or ???

Thank you again for working with me until this was completed.

Patricia

fumei
09-29-2010, 09:38 AM
I do not know of any classes/courses specifically on VBA. I wrote and teach a Word VBA course (two weeks) for our internal use, because there is so little out there.

Even Microsoft has no course material, really, for VBA.

There are some excellent books though.

PatriciaD
09-30-2010, 04:53 AM
Thanks for your help and all your time on this.. You answered my problem. I don't know how to mark this solved (unless I can't do it LOL).

I will work through some books then...I am glad we have a HUGE library system in Indy.

Thank you again!
Patricia

fumei
09-30-2010, 10:20 AM
I think Solved is under Thread Tools.