Sådan tæller vi ord med JavaScript
- Forfatter
-
-
- Navn
- Mark Buskbjerg
- Sig hej på LinkedIn
-
Målet er at bygge et værktøj til tekstforfattere, der gør det nemmere at skrive fængende og læsbare tekster. Men for at nå til det store mål, så er der tusindvis af små trin på vejen, som vi skal have styr på.
Og helt grundlæggende, så handler det hele tiden om, at værktøjet sluger teksten, analyserer det ud fra en bestemt algoritme og spytter et resultat ud.
Det er uanset, om vi skal markere alle verber (relativt svær opgave) eller skal tælle antal ord i en tekst (relativt simpel opgave).
Vi har et input, som vi bearbejder med en strimmel kode, så vi får det ønskede output.
I dag dykker vi ned i, hvordan det foregår i praksis. Og vi bruger 'antal ord i teksten' som eksempel.
Hvordan tæller vi antallet af ord?
Når vi skal tælle antallet af ord i en tekst, så skal vi først og fremmest have noget tekst. Og
Vi bruger eksemplerne her:
let exampleString = 'Jeg har plukket kokosnødder dagen lang, jeg har samlet mig en mægtig stak, bum, bum, bum! Vi har hørt den 1.000 gange.';
let exampleStringTwo = ' Ingen forstår de sorger jeg har. Ingen forstår min smerte. ';
Note: let
definerer en variabel i JavaScript, så når vi fremover skriver exampleString
fungerer det som en reference til den tekst, der står efter =
.
De to tekststrenge er selvfølgelig til at overskue. Du kan bare fedte fingrene over skærmen et ord ad gangen også tælle det.
Problemet opstår, når du har mange forskellige tekster. Og når tekstbidderne bliver lange. Det bliver hurtigt ret kedeligt at tælle ord i hele artikler, rapporter og bøger. Derfor er det her også en standardfeature i de fleste tekstbehandlingsprogrammer.
Og skal vi bygge et tekstbehandlingsværktøj til tekstforfattere, så er det et ganske fint sted at starte. Det er relativt enkelt at løse og det fungerer som et glimrende eksempel her.
Men lad os først få brudt opgaven ned i nogle logiske step:
- Tekststrengen skal renses for tegn, der er andet end ord
- Tekststrengen skal brydes op i de enkelte ord
- Antallet af de enkelte ord skal tælles
Med den viden i hånden kan vi begynde at skrive vores kode.
Vi skal have defineret en funktion til at tælle ord
Det første, vi skal have klaret er at definere en funktion, der indeholder og eksekverer vores kode på den måde som vi ønsker det.
Det kan se sådan her ud i JavaScript
function countWords(string) {
console.log(string);
}
countWords(exampleString);
Her har vi en function
, der hedder 'countWords' som kan tage en 'textString' ind og behandle den.
Derefter kalder vi funktionen og fodrer den vores 'exampleString'.
Lige nu gør vores funktion ikke så meget. Den logger egentlig bare den tekststreng, som vi fodrer den med.
Så lad os starte med at rense og klargøre vores tekststreng.
Sådan renser vi tekststrengen først
I den bedste af alle verdener, så får vi vores tekststreng ind i præcis den form, som vi ønsker den.
I virkelighedens verden, så har folk indsat mellemrum før første ord. Eller lavet dobbelte linjeskift.
Mange af de situationer kan vi forudse og tage højde for på forhånd. Nogle opdager vi, når vi for alvor begynder at teste ude i den vilde virkelighed.
En vi kan forudse er, at vi har nogle mellemrum før og efter teksten, som kan komme til at drille os.
Dem kan vi simpelthen trimme ud sådan her:
function countWords(string) {
return string.trim();
}
console.log(countWords(exampleString)); // 'Jeg har plukket kokosnødder dagen lang, jeg har samlet mig en mægtig stak, bum, bum, bum! Vi har hørt den 1.000 gange.'
console.log(countWords(exampleStringTwo)); // 'Ingen forstår de sorger jeg har. Ingen forstår min smerte.';
Vi kan i princippet begynde at rense for meget mere. I det API, der styrer (lixberegneren her)[https://tekstr.dk/app/] renser jeg for en del specialtegn. Det er ikke afgørende, når vi bare tæller ord.
Tekststrengen skal brydes op i de enkelte ord
I JavaScript kan vi nemt dele en tekststreng op med metoden '.split()'.
'split()' deler en tekststreng 'string' ind i en struktureret liste af 'substrings' og spytter dem ud som et array. Måden vi opdeler en streng på er ved at opdele dem ud fra et mønster.
Her kan et mønster eksempelvis være kommaseperation, som du måske kender fra CSV-filer. Men det kan også være mere komplicerede mønstre.
Når vi tæller ord, så er det et ret simpelt mønster, vi kigger efter. For vi kan langt hen ad vejen klare os ved at opdele på alle mellemrum i teksten.
Det kan se sådan her ud:
function countWords(string) {
return string.trim()split(' ');
}
countWords(exampleString); // returns array ['Jeg', 'har', 'plukket', 'kokosnødder', 'dagen', 'lang,', 'jeg', 'har', 'samlet', 'mig', 'en', 'mægtig', 'stak,' 'bum,', 'bum,', 'bum!', 'Vi', 'har', 'hørt', 'den', '1.000', 'gange.']
Her kalder vi altså vores countWords funktion og fodrer den med 'exampleString'.
Funktionen returnerer så en værdi til os. Det er tekststrengen, der er splittet op ved hvert mellemrum.
Det snedige kommer i sidste trin, hvor vi udnytter en feature ved et array, der gør det let at tælle.
Sådan tæller vi antallet af ord
Når vi har data i et array, så er de struktureret og der er hæftet nogle metoder på, som vi nemt kan bruge. En metode er '.length'.
Når vi kalder '.length' på et array, så får vi det præcise antal elementer, der er i vores array.
Sådan her:
console.log(['første', 'anden', 'tredje'].length); // logs 3
Det kan vi gøre direkte på det array af ord, vi skabte i forrige trin. Det ser sådan her ud:
function countWords(string) {
return string.trim().split(' ').length;
}
countWords(exampleString); // returns 22
Okay. Så vores første eksempel indeholder 22 ord.
Der er mange forskellige tilgange til at tælle ord med JavaScript.
I eksemplet har jeg for at gøre det let valt at fokusere på mellemrum som det, der adskiller ord. Men det er i virkeligheden ikke helt præcist nok. For der er situationer med linjeskift, som vi ikke får taget højde for.
Derfor er en stærkere metode at matche på et mere fintmasket mønster. Her kan vi bruge RegEx (Regular Expression) som en måde at skabe mønstrene på. Det bliver nok lidt for langt til indlægget her. Men en expression som den her '/\s+/g' matcher på:
- \s = alle såkaldte 'whitespace characters'. Det kan eksempelvis være linjeskift, mellemrum og carriage return
-
- = vores expression fanger også gentagelser, hvis du har dobbeltmellemrum eller flere linjeskift
- g = den er global, hvilket i RegEx-land betyder, at den finder alle match og ikke kun det første match.
Så en mere robust metode vil se sådan her ud:
let exampleString = 'Jeg har plukket kokosnødder dagen lang, jeg har samlet mig en mægtig stak, bum, bum, bum! Vi har hørt den 1.000 gange.';
function countWords(string) {
return string.split(/\s+/g).length;
}
console.log(countWords(exampleString)); // logs 22
Det handler selvfølgelig om mere end antal ord
Igen. Der er også andre tilgange. Og der kan være mange skøre edgecases, du skal fange på forskellige sprog. Det er en anden interessant ting ved at bygge et stykke software. At den kode du skriver oftest betragter verden som stramt struktureret og enormt forudsigelig. Den chopper bare derudaf, som du eller programmøren har bedt den om. Den aner ikke om den analyserer ord eller tal.
Overfor det er såden virkelighed som koden opererer i. Den er vild og uforudsigelig. Tekstforfattere finder på nye skøre sammensatte ord. De slæææææber på vokalerne, når de vil understrege en pointe. Eller de kopierer deres tekst fra et andet stykke software, så du skal tage højde for en masse usynlig formattering rundt om teksten, som brugeren ikke aner noget om selv.
Det er hele tiden en stræben efter et optimalt resultat. Et resultat, hvor output af koden er korrekt. Så du får det rigtige antal ord, når du beder værktøjet om at tælle. Men hvor det også går hurtigt. Hvor det virker uanset, hvor tosset du ter dig som bruger af værktøjet.