[VBA / Word 2002] Conversie van opmaakprofielen

Pagina: 1
Acties:
  • 297 views sinds 30-01-2008
  • Reageer

  • Superdeboer
  • Registratie: December 2002
  • Niet online

VBS / Word 2002

Vooraf
Ik heb wat hulp nodig, want ik kom er niet meer uit. Het volgende is het geval. Wij hebben te maken met een partij (duizenden) oude Word-documenten met de meest ranzige opmaakprofielen erin. Daar moeten we vanaf. Die tekstgedeelten moeten opmaakprofiel "standaard" krijgen, want alleen dan kan onze software de opmaak op een juiste manier verder verwerken.

Natuurlijk kan ik simpel en snel een macro maken om al die bestanden naar het profiel "Standaard" te rauzen. Maar dan zijn we een aantal simpele opmaakeigenschappen kwijt, die we als enige wél willen behouden. Dat gaat om: bold, italic, underlined, en de alinea-eigenschap "verkeerd-om inspringen" en tabstops moeten bewaard blijven.

Oplossing?
Het was mijn plan om een macro in elkaar te zetten die alle andere opmaakprofielen dan Standaard omzet naar het opmaakprofiel Standaard en als zo'n tekstgedeelte dan bold, italic of underlined is (zij het op grond van het [niet-standaard] opmaakprofiel, zij het als aanvullende style), dan wel een combinatie daarvan, dan moeten die eigenschappen daarna weer teruggezet worden.
Kop 8 + bold moet dus uiteindelijk Standaard + bold worden. Sectiehoofd + underlined moet uiteindelijk Standaard + underlined worden.
Kortom: alles wat niet "Standaard" is moet Standaard worden, met behoud van bold, italic of underline, en die paar simpele alinea eigenschappen...

Ik meende dat wel met een macro op te kunnen lossen, maar VBS is geen PHP, waar ik wel een beetje mijn weg in weet. Simpelweg het opnemen van mijn acties levert mij niet voldoende oplossingen, dus het wordt handwerk.

Mijn uitgangspunt was om heel simpel te beginnen en dat dan steeds verder uit te bouwen met extra eigenschapppen. Nou ben ik tot het onderstaande gekomen (dit staat tussen nog wat andere onzin). Dat functioneert als volgt: als een stuk tekst al "Standaard" is, wordt het met rust gelaten en wordt naar de volgende paragraaf geskipt. Als het opmaakprofiel daarvan dan niet standaard is en wél vetgedrukt, wordt het in "Standaard" omgezet.

VBScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Dim oRg As Range
    Dim oTestRg As Range
    Set oRg = ActiveDocument.Range
    With oRg.Find
        .ClearFormatting
        .Text = ""
        .Style = "Standaard"
        .Format = True
        .Forward = True
        .Wrap = wdFindStop
       
        Do While .Execute
            Set oTestRg = oRg.Duplicate
            With oTestRg
                .Collapse wdCollapseEnd
                ' dit is de simpelste variant om mee te beginnen: 
                ' als het opmaakprofiel niet "standaard is
                ' en de font-style is "vet", maak het dan "Standaard"
                If (LCase(.Style) <> "standaard") And (.Font.Bold = True) Then
                    ' onderstaande regel werkt wel, maar .Font.Italic = True niet??
                    .Style = "Standaard" 
                End If
            End With
        Loop
    End With


Probleem
Ik dacht: simpel moet wel effectief zijn, maar meteen bij de volgende stap gaat het fout. Als ik bijvoorbeeld niet die tekst in "Standaard" om wil zetten, maar in plaats daarvan .Font.Italic = True opneem op regel 21, dan gebeurt er dus helemaal niks. En dat snap ik niet... Ik heb daar inmiddels verschillende dingen geprobeerd, maar kom er niet uit.

Hulp hiermee, of betere ideeën?
Ik ben vast niet de eerste die oude documenten van hun overbodige opmaakprofielen heeft willen ontdoen bij een conversie... maar ik kon hier weinig over vinden helaas. Ook een avondje Googlen bracht mij niet op betere ideeën dan het bovenstaande.
Is er iemand die mij een stap verder kan helpen? Zit ik überhaupt wel op de goede weg hiermee? Of zijn er efficiëntere manieren om zo'n conversie van Wordbestanden aan te pakken wellicht? Alvast bedankt.

When I write my code, only God and I know what it means. One week later, only God knows.
Hell yes it's a Cuban Cigar, but I'm not supporting their economy, I'm burning their fields.


  • Lustucru
  • Registratie: Januari 2004
  • Niet online

Lustucru

26 03 2016

Moeten er de volledige opmaakprofielen uitgesloopt worden of is het voldoende als de gebruikte opmaakprofielen standaard -uitgezonderd de instellingen die je wilt behouden- opgemaakt worden? dat laatste is namelijk wel wat eenvoudiger.

Dat .font.italic niet veel doet is wel te begrijpen. Vlak daarvoor collapse je namelijk de range, dus bljft er effectief niks over waar het op toegepast zou moeten worden.

[ Voor 6% gewijzigd door Lustucru op 26-08-2007 21:13 ]

De oever waar we niet zijn noemen wij de overkant / Die wordt dan deze kant zodra we daar zijn aangeland


  • Superdeboer
  • Registratie: December 2002
  • Niet online
Ah, het is dat eerste: juist de naam van het opmaakprofiel zit dwars. ;(
Het moet echt allemaal "Standaard" zijn, omdat onze software de documenten vervolgens verder verwerkt op basis van een sjabloon, waar in feite alleen "Standaard" in zit. Ik heb al gekeken of ik de meest voorkomende opmaakprofielen uit de legacy documenten aan kan maken in dat sjabloon met de door mij gewenste opmaak, maar dat is lang niet waterdicht genoeg. Vandaar dat ik nu een macro wil maken, die iedere gebruiker met de hand kan uitvoeren op het document voordat het verder verwerkt wordt. Zodoende moeten dan de opmaakprofielen al gestript worden (en de meest basic layout dus wel behouden) voordat we aan verdere processing toekomen. :)

Dat collapsen van de gevonden range was de enige manier die ik kon vinden om uit te komen bij tekstblokken die niet "Standaard" als profiel hebben... Maar ik zie nu inderdaad dat je dan niks meer overhoudt... :P

When I write my code, only God and I know what it means. One week later, only God knows.
Hell yes it's a Cuban Cigar, but I'm not supporting their economy, I'm burning their fields.


  • Lustucru
  • Registratie: Januari 2004
  • Niet online

Lustucru

26 03 2016

Als de gebruiker alleen alinea gebonden opmaakprofielen heeft gebruikt, én je het niet erg vindt om losse tekenopmaak te verliezen binnen die standaardprofielen dan zou ik gewoon de paragrafen enumeren, het opmaakprofiel uitlezen en weggooien om er volgens de opmaakkenmerken die wilt behouden los toepassen.

[ Voor 14% gewijzigd door Lustucru op 26-08-2007 22:44 ]

De oever waar we niet zijn noemen wij de overkant / Die wordt dan deze kant zodra we daar zijn aangeland


  • Superdeboer
  • Registratie: December 2002
  • Niet online
Hmmm, nou ga je een stapje te hard. :P
Het klinkt me wel in de oren als de oplossing die ik toe had willen passen... maar mijn kennis van VBS is niet goed genoeg om dat zomaar uit te kunnen voeren. Enumeren van paragrafen... wat is dat? Ik vind daar niets over in de documentatie. Zoals ik nu begonnen was (waarvan ik dus moet toegeven dat het afkijkwerk van opgeGooglde informatie is), kan ik daarmee verder, of moet ik 't anders doen? :)

edit:

Ik heb wel zitten kijken naar het onderstaande stukje code, dat mij met mijn simpele PHP-kennis veel bekender voorkomt:
VBScript:
1
2
3
4
5
6
7
8
    Dim currentParagraph As Paragraph

    ' Pas Standaard toe op elke "niet-Standaard" alinea.
    For Each currentParagraph In ActiveDocument.Paragraphs
        If LCase(currentParagraph.Style) <> "standaard" Then
            currentParagraph.Style = "Standaard"
        End If
    Next currentParagraph

Maar ook daarbij mis ik volgens mij weer de boot bij het selecteren van het stuk tekst waar ik wat mee wil doen.
Volgens mij werkt dit op zijn minst om afwijkende profielen eruit te slopen. Nou nog uitzoeken hoe bold, italic en underlined teruggezet moeten worden en uitlijningsinstellingen toegepast moeten worden.

[ Voor 52% gewijzigd door Superdeboer op 27-08-2007 09:49 ]

When I write my code, only God and I know what it means. One week later, only God knows.
Hell yes it's a Cuban Cigar, but I'm not supporting their economy, I'm burning their fields.


Verwijderd

zoals Lustucru zegt: bekijk of een paragraaf niet-Standaard is, zo ja, dan ga je eerst de huidige stijl van deze paragraaf onderzoeken op de aanwezigheid van bold, italics, die je opslaat in een variabele. daarna wijzig je de stijl naar standaard en pas je de eerder opgeslagen stijleigenschappen hier opnieuw op toe.

terloops wil ik wel even opmerken dat net dit door ervaren word gebruikers als ranzig wordt beschouwd. het is immers de bedoeling van netjes stijlen toe te kennen aan paragrafen die verschillende opmaak moeten hebben, waarbij de opmaakinformatie liefst volledig vervat zit in de stijl (en dus niet Standaard+losse bijkomende opmaak zoals je nu gaat toepassen)

  • Superdeboer
  • Registratie: December 2002
  • Niet online
Nah, ik ben nu een stuk verder, thanks! d:)b
_heretic_, ik ben met je eens dat het lelijk is en in strijd met het idee van Word over tekststructurering (of HTML for that matter), maar als het niet kan zoals het moet, dan moet het zoals het kan. Ik kan de software niet aanpassen, wel onze invoer. En als die invoer in de afgelopen tien jaar maar consequent gebruik had gemaakt van de verschillende stijlen dan ging dat heel simpel, maar na 5 compleet verschillende opmaken van "Kop 5" tegen te zijn gekomen, denk ik dat mijn huidige oplossing wel het meest efficiënt is op het moment.

Het werkt vrij aardig nu... alleen het terugzetten van indents/tabstops krijg ik nog niet voor elkaar (en zit dus nog niet in het onderstaande script).
VBScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   Dim currentParagraph As Paragraph

    ' Pas Style toe op elke links uitgelijnde alinea.
    For Each currentParagraph In ActiveDocument.Paragraphs
        If LCase(currentParagraph.Style) <> "standaard" Then
            If currentParagraph.Range.Font.Bold = True Then fBold = True
            If currentParagraph.Range.Font.Italic = True Then fItalic = True
            If currentParagraph.Range.Font.Underline = wdUnderlineSingle Then fU = True
            ' now convert to Standaard
            currentParagraph.Style = "Standaard"
            If fBold = True Then currentParagraph.Range.Font.Bold = True
            If fItalic = True Then currentParagraph.Range.Font.Italic = True
            If fU = True Then currentParagraph.Range.Font.Underline = wdUnderlineSingle
        End If
    Next currentParagraph

When I write my code, only God and I know what it means. One week later, only God knows.
Hell yes it's a Cuban Cigar, but I'm not supporting their economy, I'm burning their fields.


Verwijderd

de indents en tabstop kan je onderzoeken met 'currentparagraph.tabstops' & currentparagraph.format.leftindent & .rightindent.
tevens is voor het opslaan en instellen van de eigenschappen die je nu hebt geen if constructie nodig:
Visual Basic:
1
2
3
4
5
6
'...opslaan
fBold=currentParagraph.Range.Font.Bold
fU=currentParagraph.Range.Font.Underline
'...instellen
currentParagraph.Range.Font.Bold = fBold
currentParagraph.Range.Font.Underline=fU

  • Superdeboer
  • Registratie: December 2002
  • Niet online
Ah veel beter... dat is een stuk leesbaarder natuurlijk. Kun je zien hoe je je blind zit te staren als je een taal niet machtig bent.
Dit werkt perfect, maar de tabstops blijft een gevecht (indenting lukt overigens goed). Gewoon doorgeven door bla = currentparagraph.tabstops en na het strippen van de stijlen gewoon weer currentparagraph.tabstops = bla te doen, lukt niet... dan krijg ik een fout 450, omdat ik argumenten mee moet geven bij het vullen van bla. Voor zover ik het begrijp is currentParagraph.tabstops een array van overige informatie, dus ik kan me daar iets bij voorstellen... Toen had ik bedacht om die array dan maar eens door te lopen en zo ben ik tot het onderstaande gekomen:
VBScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    Dim currentParagraph As Paragraph
    Dim varTab As Variant
    Dim tabArr As Variant

    For Each currentParagraph In ActiveDocument.Paragraphs
        If LCase(currentParagraph.Style) <> "standaard" Then
            fBold = currentParagraph.Range.Font.Bold
            fItalic = currentParagraph.Range.Font.Italic
            fU = currentParagraph.Range.Font.Underline
            ' Wandel door de tabstops in deze paragraaf
            For Each varTab In currentParagraph.TabStops
               If varTab.CustomTab = True Then
                  tabArr = PointsToCentimeters(varTab.Position)
               End If
            Next
            '## onderstaande regel levert fout 450 op...
            'tabsetting = currentParagraph.TabStops
            leftindentsetting = currentParagraph.Format.LeftIndent
            rightindentsetting = currentParagraph.Format.RightIndent
            firstlineindentsetting = currentParagraph.Format.FirstLineIndent
            ' now convert to Standaard
            currentParagraph.Style = "Standaard"
            currentParagraph.Range.Font.Bold = fBold
            currentParagraph.Range.Font.Italic = fItalic
            currentParagraph.Range.Font.Underline = fU
            '## onderstaande regel werkt dus niet; zie line 16 en 17
            'currentParagraph.TabStops = CentimetersToPoints(tabsetting)
            For Each tabPos In tabArr
                currentParagraph.Range.ParagraphFormat.TabStops.Add Position:=CentimetersToPoints(tabPos)
            Next
            currentParagraph.Format.LeftIndent = leftindentsetting
            currentParagraph.Format.RightIndent = rightindentsetting
            currentParagraph.Format.FirstLineIndent = firstlineindentsetting
        End If
    Next currentParagraph


Het gaat dus fout in regel 28 (waar tot mijn verbazing line 10-15 foutloos gepasseerd worden), met fout 13, typen kopen niet overeen. Ik ben er echt bijna nu, maar dat object TabStops blijkt te moeilijk om het nou even gauw af te maken. ;(

When I write my code, only God and I know what it means. One week later, only God knows.
Hell yes it's a Cuban Cigar, but I'm not supporting their economy, I'm burning their fields.


  • Lustucru
  • Registratie: Januari 2004
  • Niet online

Lustucru

26 03 2016

Dat doorlopen van de tabs collectie werkt zo niet, omdat je telkens hethele array instelt op een enkele waarde. Maard at hoeft ook niet, de hele tabstops collectie kun je direct gebruiken. Zitten alleen wat eigenaardigheden aan:
code:
1
2
3
4
Dim t as tabstop
set t=currentparagraph.tabstops
...
currentparagraph.tabstops = t

is correct qua syntax, maar werkt niet, omdat T alleen een verwijzing bevat naar het tapstops object en dat wordt schoongemaakt bij het toepassen van het standaardprofiel :X

dus even in een apart object geparkeerd:
code:
1
2
3
4
Dim p as NEW ParagraphFormat
p.tabstops = cp.tabstops
...
cp.tabstops = p.tabstops


:P

Blijf je natuurlijk wel met het probleem zitten dat door het veranderen van lettertype/grootte het uiteindelijke resultaat toch anders kan uitvallen dan je bedoelde :)

edit:
VBA is iets anders dan VBS, fyi

[ Voor 31% gewijzigd door Lustucru op 28-08-2007 10:02 ]

De oever waar we niet zijn noemen wij de overkant / Die wordt dan deze kant zodra we daar zijn aangeland


  • PolarBear
  • Registratie: Februari 2001
  • Niet online
Lustucru schreef op dinsdag 28 augustus 2007 @ 09:49:
edit:
VBA is iets anders dan VBS, fyi
Het is inderdaad heel vervelend dat VB, VBA en VBS op subtiele punten verschillen. Heeft menig uurtje gekost denk ik.

Overigens hulde voor de uitgebreide topicstart _/-\o_

* PolarBear gaat de volgende keer weer ontopic reageren.

[ Voor 17% gewijzigd door PolarBear op 28-08-2007 09:59 ]


  • Superdeboer
  • Registratie: December 2002
  • Niet online
Jaaaaa, dat is het! Helden!
Had ik daar nou zelf achter (moeten) kunnen komen met alle documentatie die ik heb gelezen? :$

Bij de meeste probleemtopics die ik op internet vind, staat als antwoord: neem 't even op met de macro-recorder en kijk wat er gebeurt, dan kun je daar misschien wat mee. Voor iets als dit, wat op zich vrij basic handelingen zijn, heb je al niks aan die hele macro-recorder. :)

Maar goed, hartstikke bedankt voor de hulp!
De code ziet er nu zo uit en werkt voor de eerste testcases grandioos!
VBScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    Dim currentParagraph As Paragraph
    Dim p As New ParagraphFormat

    For Each currentParagraph In ActiveDocument.Paragraphs
        If LCase(currentParagraph.Style) <> "standaard" Then
            'Put layout we want to preserve in variables
            fBold = currentParagraph.Range.Font.Bold
            fItalic = currentParagraph.Range.Font.Italic
            fU = currentParagraph.Range.Font.Underline
            p.TabStops = currentParagraph.TabStops
            leftindentsetting = currentParagraph.Format.LeftIndent
            rightindentsetting = currentParagraph.Format.RightIndent
            firstlineindentsetting = currentParagraph.Format.FirstLineIndent
            'Now convert all legacy styles to Standaard
            currentParagraph.Style = "Standaard"
            'Apply preserved layout to this paragraph
            currentParagraph.Range.Font.Bold = fBold
            currentParagraph.Range.Font.Italic = fItalic
            currentParagraph.Range.Font.Underline = fU
            currentParagraph.TabStops = p.TabStops
            currentParagraph.Format.LeftIndent = leftindentsetting
            currentParagraph.Format.RightIndent = rightindentsetting
            currentParagraph.Format.FirstLineIndent = firstlineindentsetting
        End If
    Next currentParagraph

When I write my code, only God and I know what it means. One week later, only God knows.
Hell yes it's a Cuban Cigar, but I'm not supporting their economy, I'm burning their fields.

Pagina: 1