Een eenvoudige lijst bewerken in Word met VBA

Door Ralph Komen

Verveelt u zich ook zo snel als u steeds hetzelfde moet doen? Ik wel. En als er zich een gelegenheid voordoet om zo’n zich steeds herhalende taak via een macro te doen, dan investeer ik daar liever mijn tijd in. Niet alleen omdat het op de lange duur tijd bespaart, maar ook omdat ik da gewoon leuk vind. OK, uw baas zal voor dat laatste argument wat minder gevoelig zijn, maar het eerste zal hem of haar zeker overtuigen. Zeker als u ook anderen van uw investering laat meeprofiteren door uw macro’s met hen te delen. Als u niet erg bekend met macro’s of Visual Basic for Applications (VBA), lees dan verder en ik zal u de komende twee dagen door een eenvoudig voorbeeld heen leiden dat u de kracht van VBA laat zien. De concepten die ter sprake komen zijn algemeen toepasbaar in de Office-programma’s, niet alleen in Word.

Een tijd geleden las ik een ingezonden brief in een computertijdschrift met een schijnbaar simpele vraag. Het serversysteem van de gebruiker produceerde lijsten van items in een tekstbestand. Die lijsten moesten dan opgeschoond worden voordat ze weer verder het systeem in konden: alle dubbele items moesten er uit gehaald worden. Zeker als het om lange lijsten gaat - en in het geval van de briefschrijver ging het om duizenden items – is dat handmatig een zeer tijdrovende taak, met grote kans op fouten. En aangezien deze lijsten meerdere malen per week werden gegenereerd, schreeuwde dit om een macro.

Het antwoord dat deze ingezonden-briefschrijver kreeg van de redacteur van het tijdschrift was dat dit in Word eenvoudigweg niet kan, zelfs niet met een macro. Het advies was dan ook de lijst in Access te importeren, de dubbele records er uit te filteren en de lijst weer te exporteren. Zie het artikel Dubbele records in Access 2002 zoeken en verwijderen voor meer informatie hierover. Zelfs Excel werd niet als optie genoemd, hoewel ook daarin deze mogelijkheid bestaat. Zie hiervoor Delete duplicate rows from a list in Excel (Engelstalig).

Maar ik realiseerde me dat niet iedereen zomaar eventjes een Access-database maakt en daarin een filter-query ontwerpt om dubbele items te verwijderen. Als men al Access heeft… En de methode in Excel werkt weliswaar, maar heeft wel erg veel stappen. Overigens is dit een van de prachtige nieuwe opties in Excel 2007, zie het artikel Filteren op unieke waarden of om dubbele waarden te verwijderen. Met één druk op de knop heeft u uw dubbele items verwijderd!

Allemaal leuk en aardig, maar de briefschrijver had nog steeds geen antwoord op de vraag hoe dit eenvoudig te realiseren is in Word. En omdat ik nooit te beroerd ben om iets in VBA te proberen, besloot ik de uitdaging aan te nemen en een macro te maken die dit probleem elegant en simpel in Word zou oplossen.

Ik heb macro’s geschreven sinds WordPerfect 4.1 voor MS-DOS. Mijn eerste macro in Word was in versie 2.0. Jawel, de goede oude tijd van WordBasic. Herinnert iemand zich dat nog? Afijn, we zijn intussen een stuk verder en hebben in VBA een zeer krachtige programmeeromgeving en je kan het zo gek niet bedenken of het is in VBA te maken. Als u niet heel erg vertrouwd bent met VBA, lees dan het artikel Inleiding tot aangepaste macro's in Excel. Dit is een algemene inleiding in VBA en maakt u vertrouwd met concepten als methoden, eigenschappen, de programmeeromgeving, enzovoort, die op alle Office-programma’s van toepassing zijn. Een andere, goede introductie is de gratis online training Get in the loop with Excel macros (Engelstalig). Voor deze training geldt eveneens: hoewel de voorbeelden in Excel worden gegeven, zijn de concepten op alle Office-programma’s van toepassing.

OK, laten we nu eens die macro gaan schrijven die de dubbele items uit een Wod-document haalt. Het document heeft elk afzonderlijk item in een aparte alinea en er is geen kopregel (ik zal ook de aanpassingen geven die nodig zijn al dat wel het geval is). Iets als dit:

Argentinië

Zwitserland

Tsjaad

China

Rusland

China

Voordat ik in de code duik, begin ik meestal met een kort overzicht van de stappen die ik moet maken om die stappen vervolgens in code om te zetten. In dit geval moeten we het volgende doen:

  • De lijst sorteren zodat gelijke items onder elkaar staan

  • Elke alinea n met alinea n - 1 vergelijken

  • Als n = n -1 alinea n verwijderen

  • Herhaal dit voor alle alinea’s

Dat ziet er redelijk eenvoudig uit toch? Er zitten echter wel wat addertjes onder het gras, maar die zijn ook weer eenvoudig te omzeilen. Voordat we in Word een macro kunnen schrijven, moeten we eerst een module maken met een procedure. Zo’n procedure is de eigenlijke macro, en de module is niet meer dan en container voor macro’s. Start Word en druk op Alt + F11 om de Visual Basic Editor te openen (de VBE: de programmeeromgeving). Kijk aan de linkerkant naar de Project Explorer (klik Ctrl + R als deze niet zichtbaar is), en zorg dat de Normaal-sjabloon geselecteerd is. Kies dan uit het menu Invoegen, Module. Dit voegt een blanco module toe aan uw standaard of Normal sjabloon, waardoor de macro in al uw documenten beschikbaar komt. De module zal ws.  Module1 of iets dergelijks heten. Die naam kunnen we veranderen, maar voor nu laten we het maar even zo. Het kan ook zijn dat uw module niet helemaal blanco is maar tekst bevat als Option Explicit: negeer dat voor dit moment.

Alle code die we willen uitvoeren moet in een zogenaamde procedure zitten. Om deze toe te voegen tikt u de volgende regels in uw module:

Sub VerwijderDubbeleRegels()
'hier komt de code
End Sub

Nu we de procedure hebben gemaakt kunnen we daar onze code tussen invoegen.

Stap 1: Sorteren

Als eerste moeten we de lijst sorteren. Er zijn zoveel opties en parameters voor het sorteren in Word, dat ik dat meestal opneem en vervolgens met eventuele aanpassingen in mijn procedure knip-en-plak. Als u wilt weten hoe u een macro opneemt, zie Een macro maken. Hier is de code voor het sorteren van alinea’s in een heel Word-document:

Selection.Sort ExcludeHeader:=False, FieldNumber:="Paragraphs", _
SortFieldType:=wdSortFieldAlphanumeric, SortOrder:=wdSortOrderAscending

Het sorteren gebeurt door de .Sort methode toe te passen op de selectie. Als er geen selectie is (en daar moeten we dus in de code voor zorgen) neemt Word het gehele document als selectie. De parameters geven aan dat er geen koptekst of titel is (ExcludeHeader) te sorteren op hele alinea’s (FieldNumber) and te sorteren op tekst (SortFieldType) en in oplopende volgorde (SortOrder). Tip: Mocht u een VBA-term in een macro niet begrijpen, selecteer dan die term en klik op F1. De Help in VBA is zeer uitgebreid en geeft behalve informatie ook handige voorbeelden om u op weg te helpen.

Stap 2: Alinea’s vergelijken

Nu onze lijst gesorteerd is kunnen we twee opeenvolgende alinea’s vergelijken en indien identiek één van de twee verwijderen. En dit moeten we voor elk paar alinea’s doen tot we het einde van het document bereikt hebben. Om te bepalen hoeveel alinea’s er zijn, en waar we moeten stoppen, gebruiken we een variabele iParCount om het aantal alinea’s in op te slaan. Dat ziet er dan zo uit:

iParCount = ActiveDocument.Paragraphs.Count

En zo gebruiken we ook twee variabelen om de tekst van de twee te vergelijken alinea’s op te slaan:

strLast = ActiveDocument.Paragraphs(n).Range.Text 
strPrevious = ActiveDocument.Paragraphs(n - 1).Range.Text

Stap 3: Een dubbele alinea verwijderen

Nu moeten we de twee alinea’s vergelijken en zonodig de dubbele verwijderen. Hiervoor gebruiken we een If-constructie en als die waar is (en de alinea’s dus gelijk zijn), selecteren we de laatste en verwijderen die:

If strLast = strPrevious Then
ActiveDocument.Paragraphs(n).Range.Select
Selection.Delete
End If

Stap 4: Herhalen en nog eens herhalen

Nu kunnen we alles samenbrengen met een For … Next-lus. (Zie voor informatie over de diverse recursieve methodes in VBA de Engelstalige online training Get in the loop with Excel macros (Engelstalig).)

Sub VerwijderDubbeleRegels()
'Vier variabelen declareren die we nodig hebben
Dim iParCount As Integer
Dim n As Integer
Dim strLast As String
Dim strPrevious As String
'Sorteren (zonder kopregel)
With Selection
.Sort ExcludeHeader:=False, FieldNumber:="Paragraphs", _
SortFieldType:=wdSortFieldAlphanumeric, _
SortOrder:=wdSortOrderAscending.
HomeKey unit:=wdStory, Extend:=False
End With
'Het aantal regels bepalen
iParCount = ActiveDocument.Paragraphs.Count
‘Herhalen voor elke alinea
For n = 1 to iParCount
strLast=ActiveDocument.Paragraphs(n).Range.Text
strPrevious=ActiveDocument.Paragraphs(n - 1).Range.Text
If strLast=strPrevious Then
ActiveDocument.Paragraphs(n).Range.Select
Selection.Delete
End If Next
End Sub

Klaar! Nou… nog niet helemaal. U heeft het waarschijnlijk allang zelf gezien: als deze code wordt losgelaten op een document, loopt u tegen een probleem aan. Stel dat u een lijst van tien items heeft en u begint te vergelijken bij alinea 1 en 2, dan 2 en 3, 3 en 4, enzovoort. Als er zo nu en dan een dubbele alinea bij zit en u deze verwijdert, zijn er geen 10 alinea’s meer, terwijl de code wel tot die tiende wil doorgaan. Zelfs als er maar één alinea wordt verwijderd loopt de code fout. En het is zeker bij grote lijsten onvoorspelbaar hoeveel dubbele items verwijderd worden. Nu zouden we dit kunnen afvangen in de code en domweg de lus verlaten met een foutafhandeling, maar het kan eenvoudiger en eleganter. De oplossing is eenvoudig aan het einde van het document te beginnen en naar het begin terug te werken. In een For … Next-lus kunnen we via de optie Step, niet alleen bepalen hoeveel we per stap opschuiven, maar ook de richting aangeven. Een negatief getal geeft daarbij aan dat we in aflopende richting gaan. Dat ziet er dan zo uit:

For n = iParCount To 2 Step -1
   …
Next

Op deze manier voorkomen we dat de code meer alinea’s wil vergelijken dan in het document staan.

De afronding

Een van de dingen die we nu nog moeten doen is commentaar aan de code toevoegen. Op die manier weten we nog wat we aan het doen waren als we de code over 6 maanden of 6 jaar nog eens bekijken. Of als iemand anders naar onze code kijkt…

We zullen ook de schermbijwerking uitzetten terwijl onze code loopt. Dit is in het algemeen aan te raden als we zaken uitvoeren die veel wijzigingen in een document maken. Het voorkomt dat het document of de tekst continu voor de gebruiker heen en weer springt en het maakt de macro daardoor vaak nog sneller ook. En omdat we de schermbijwerking uitzetten, moeten we via de statusbalk wel de gebruiker laten weten dat we nog bezig zijn.

En dat ziet er dan zo uit:

Sub VerwijderDubbeleRegels()
'Vier variabelen declareren die we nodig hebben
Dim iParCount As Integer
Dim n As Integer
Dim strLast As String
Dim strPrevious As String 
'Het bijwerken van het scherm uitzetten
Application.ScreenUpdating = False
'Sorteren (zonder kopregel)
With Selection
.HomeKey unit:=wdStory, Extend:=False
.Sort ExcludeHeader:=False,
FieldNumber:="Paragraphs", _
SortFieldType:=wdSortFieldAlphanumeric, _
SortOrder:=wdSortOrderAscending
End With
'Het aantal regels bepalen
iParCount = ActiveDocument.Paragraphs.Count
'Vanaf de laatste regel beginnen
For n = iParCount To 2 Step -1
'Op de statusblak laten weten dat we er nog zijn...
Application.StatusBar = "Bezig met bijwerken regel" & n & " van "
& iParCount
'De twee regels inlezen die we willen vergelijken
strLast = ActiveDocument.Paragraphs(n).Range.Text
strPrevious = ActiveDocument.Paragraphs(n - 1).Range.Text
'Als de twee regels hetzelfde zijn verwijderen we de tweede
If strLast = strPrevious Then
ActiveDocument.Paragraphs(n).Range.Select
Selection.Delete
End If
Next
'Het scherm weer gewoon laten bijwerken en de statusbalk leegmaken
Application.ScreenUpdating = True
Application.StatusBar = ""
'Even laten weten dat we klaar zijn 
MsgBox "Klaar!!!"
End Sub

Sla uw module op, sluit de VBE en sla al uw werk op. Denk er om dat deze code te gebruiken is op eigen risico: maak een backup van uw documenten vóór u de code er op los laat. Dat is sowieso een goed advies dat u altijd ter harte moet nemen… Als u zoals aangegeven de macro heeft opgeslagen in uw standaardsjabloon kunt u deze macro in elk Word-document gebruiken. Open een document en druk op Alt + F8 om de lijst met beschikbare macro’s te zien en selecteer dan deze macro en klik op Uitvoeren.

Ik heb deze macro zelf geprobeerd met documenten met ruim 1000 alinea’s waarbij de code er zo’n seconde of 10 over deed om de dubbele alinea’s er uit te halen. De snelheid hangt natuurlijk af van de lengte van de alinea’s en de snelheid van uw computer. Natuurlijk, het kostte me 15 minuten om de macro te schrijven – en u om dit artikel te lezen – maar zelfs in een half uur zou ik die lijst met 1000 alinea’s waarschijnlijk niet met de hand hebben kunnen doorlopen. En dan ook nog zonder fouten te maken. En zeker als dit iets is wat regelmatig terugkeert, is die investering meer dan de moeite waard. Dan heeft u weer tijd teruggewonnen waarin u VBA-handboeken kunt lezen...

Variaties

Wat als u wel een koptekst of titel in het document heeft? De kans lijkt me klein dat het eerste item in de lijst hetzelfde is as de titel, maar laten we die kans maar niet nemen en de code aanpassen. Dat moet op twee plaatsen. Ten eerste moet u er bij het sorteren rekening mee houden: zet de parameter ExcludeHeader op Truein plaats van False.Ten tweede moet u bij het doorlopen en vergelijken van de alinea’s stoppen voordat u bij de titel bent:

For n = iParCount To 3 Step -1

Andere variaties zijn het aanpassen van de macro zodat u deze ook op een willekeurige selectie werkt: probeer het maar eens! En u kunt een knop op de werkbalk maken zodat u de macro snel uit kunt voeren. En er zijn waarschijnlijk nog veel meer andere variaties mogelijk: leef uzelf uit!

Tenslotte moeten we natuurlijk nog foutafhandeling toevoegen, maar dat is teveel van het goede voor deze keer. Als u meer informatie zoekt over het programmeren in VBA, bekijk dan de volgende artikelen op Office Online:

Voor diegenen die serieus aan de slag willen gaan moeten zeker de aanschaf overwegen van het VBA Developer’s Handbook van Ken Getz en Mike Gilbert. Elk boek van deze auteurs over het programmeren in Office (of waar dan ook) is zeer de moeite waard. Het VBA Developer’s Handbook is uit 1999, maar nog steeds een onuitputtelijk bron van inspiratie. Er is een tweede editie uit 2001, maar alleen met harde omslag. Kijk bij de diverse online boekenwinkels voor prijzen en beschikbaarheid.

Uw vaardigheden uitbreiden
Training verkennen
Als eerste nieuwe functies krijgen
Deelnemen aan Office Insiders

Was deze informatie nuttig?

Bedankt voor uw feedback.

Hartelijk dank voor uw feedback! Het lijkt ons een goed idee om u in contact te brengen met een van onze Office-ondersteuningsagents.

×