DA/LanguageTool/UdviklerGuide

LanguageTool-udviklerguide

Delvist forældet
Informationen på denne side er delvist forældet.

Projektet lå tidligere under SVN i en anden mappestruktur. Nu ligger det på Github på adressen https://github.com/languagetool-org/ med en ny mappestruktur.

Filnavnene og filstierne på denne side er muligvis ikke fuldstændigt opdaterede til den nye struktur.

Overordnet
LanguageTool er en grammatikkontrol til bl.a. LibreOffice (som plugin), men fungerer også som et selvstændigt program, og som plugin til f.eks. Chrome og Firefox.

Den er bygget i programmeringssproget Java og dokumentstandarden xml. De fleste tilføjelser er lavet i xml-dokumenter, hovedsageligt grammar.xml og disambiguation.xml. Når en regel ikke kan skrives ud fra et regulært udtryk, eller blot er for omfattende til at blive beskrevet med et regulært udtryk, kan den tilføjes via Java-delen.

Grammatikkontrollen er under konstant udvikling og den nyeste version kan findes her: http://sourceforge.net/projects/languagetool/.

Der bruges Git til versionsstyring. Med Git kan man hente den nye version med denne kommando (på Linux i hvert fald; er ikke testet på Windows):

git clone https://github.com/languagetool-org/languagetool.git

Bemærk at den nyeste version med denne kommando bliver lagt i en undermappe kaldet  i din aktive mappe.

Man kan opdatere sin version til den nyeste med kommandoen

git pull

Når en ændring er lavet, sendes en mail til mailinglisten med differencen mellem den nye og den gamle udgave – en såkaldt "diff". Man får differencen med kommandoen

git diff

(Bemærk at den aktuelle mappe skal være roden af -mappen for at få differencen på hele LanguageTool).

De filer, du kan redigere i, når du vil arbejde på den danske grammatikkontrol, ligger flere steder.

I undermapper til mappen  (Github) ligger:
 * Dokumentet til grammatikregler: . (Github)
 * Dokumentet til flertydighed (disambiguation): . (Github)

I undermapper til mappen  (Github) ligger:
 * Dokumentet til falske venner (false-friends; udenlandske ord der ligner danske, men med anden betydning):  (indeholder også falske venner for andre sprog). (Github)
 * Dokumentet til definition af sætninger:  (søg på 'danish' for at finde den danske del) (Github)

Alle dokumenter bliver skrevet i xml version 1.0 og med tegnkodning efter UTF-8-standarden. Derudover følger de respektive xml-dokumenter en struktur, som er beskrevet i .xsd-dokumenterne, som ligger i mapperne /resource og /rules. Disse skal man ikke redigere i.

Grammar.xml indeholder grammatikreglerne og skrives i regulære udtryk. Disse udtryk kan være alt fra meget simple til meget komplekse; du kan læse mere om regulære udtryk i afsnittet Grammatikregler nedenfor eller her: http://www.regular-expressions.info.

Når man f.eks. har lavet en ny dansk grammatikregel ved at redigere i grammar.xml, skal denne afleveres til en ansvarlig, som så vil tilføje ('committe') ændringerne til den næste version af LanguageTool. Dette gøres ved at bruge  som beskrevet ovenfor.

Mailinglisten melder man sig til her: https://lists.sourceforge.net/lists/listinfo/languagetool-devel.

Hunspell er ordbogen, som LanguageTool går ud fra. Ordbogen indeholder ord med mærker, såkaldte 'tags', der beskriver ordets klasser. Du kan finde en oversigt over tags på de danske ord under  (Github). Et ord kan f.eks. være et substantiv (navneord) i en bestemt form. Et ord kan have flere ordklasser; f.eks. kan 'jeg' både være et substantiv og et pronomen, og tagget vil derfor se således ud:

Jeg[jeg/sub:ube:sin:neu:nom,jeg/pron:sin:nom].

Grammatikkontrollen bruger ordbogen og taggene, og det er ikke umiddelbart meningen at du skal redigere i ordbogen, hvorfor kildefilerne ikke er tilgængelige. Du kan dog meddele evt. mangler og fejl på det danske forum.

Det er vigtigt at teste nye regler. Kan de kompileres? Er logikken korrekt? Og hvordan reagerer f.eks. LibreOffice på den nye regel? Læs mere i afsnittet Testning nedenfor.

Prøv generelt at følge samme struktur i koden som allerede brugt, og brug altid mellemrumstegn, når du indrykker koden. God kodeskik er vejen frem. Derudover er det vigtigt at huske på, at grammatikreglerne/rettelserne er til for at hjælpe, ikke bremse brugeren. Undgå at lave regler med undtagelser, som ikke håndteres, og diskuter evt. med en anden eller de andre danskere, der arbejder på LanguageTool, om en given regel vil give mening eller har for mange eller for vigtige undtagelser. Det kan være en udfordring at formulere en regel, som ikke fanger forkerte sætninger. Som udgangspunkt skal man undgå regler, der fanger noget forkert. Afprøv derfor også altid din nye regel på et omfangsrigt og varieret korpus (samling af tekster), så de fleste fejl i reglen kan opdages og ændres, inden du committer reglen til SVN.

Hvis man har spørgsmål om noget omkring LanguageTool eller svn, kan man altid prøve at skrive til mailinglisten. Folk her er meget hjælpsomme.

Hent dansk ordbog/stavekontrol til LibreOffice her: http://da.libreoffice.org/hent-libreoffice/

Links

 * http://www.languagetool.org/
 * DA/LanguageTool/Regler
 * http://languagetool.wikidot.com
 * http://da.libreoffice.org/hent-libreoffice/

Grammatikregler
Grammatikreglerne er skrevet i xml og bruger regulære udtryk. Hvad der ikke kan beskrives af regulære udtryk, eller blot meget besværlige regulære udtryk, kan implementeres gennem Java-delen.

Et godt udgangspunkt i at lære at skrive grammatikregler, er at se på allerede lavede regler. Mange af disse følger en simpel struktur, som ofte kan kopieres og kort redigeres til at passe til ens egen, nye regel.

Derudover giver siderne http://wiki.languagetool.org/tips-and-tricks og http://www.languagetool.org/development en nogenlunde introduktion til koncepterne bag.

Derudover er http://www.regular-expressions.info en god side til at læse/lære om regulære udtryk, men dette er ikke nødvendigt til simple regler.

En sætning består af en række enkeltdele, kaldet s, som hver er enten et ord eller et grammatisk skilletegn. Når vi vil matche på en del af en sætning, vil vi fange et mønster, kaldet et. Dette mønster beskriver en fejlagtig delsætning, som kan være enten hele sætningen eller et enkelt ord. Vi beskriver et -element ud fra en række  -elementer.

Et eksempel på en simpel regel:

 excl .  Eksklusive forkortes ekskl. https://wiki.documentfoundation.org/DA/LanguageTool/Regler#Ekskl._og_inkl. Mulig stavefejl. Jeg bestiller en computer excl. mus. Computeren er ekskl. tastatur.

Reglen fanger ordet "excl.", som ikke er et godtaget dansk ord og hvor der sandsynligvis skulle have stået 'ekskl.' (eksklusive). Bemærk at punktum er en seperat.

Vi gør brugeren opmærksom på fejlen (eller i nogle tilfælde blot den mulige fejl) i en besked,, hvor vi også angiver et forslag,  , til hvad der sandsynligvis skulle have stået.

Elementet  er valgfrit, men vi prøver i den danske grammatikkontrol at beskrive de fejl, LanguageTool fanger, på vores wiki og linke til disse. Wikien er samtidig en god mulighed for at linke videre til sider, som argumenterer for, at det faktisk er en fejl, der beskrives. Se evt. DA/LanguageTool/Regler for eksempler.

Elementet  er blot en kort udgave af beskeden.

Derefter følger et antal eksempler,, som kan indeholde et vilkårligt antal korrekte og forkerte eksempler, dog minimum et af hvert. Dette er en rigtig god måde at teste sin regel på, da disse fungerer som automatiske unittests. Man bør, ved mere komplicerede regler, lave flere af disse, så man tester på alle grænsetilfælde. I eksempler er det ikke nødvendigt at beskrive rettelsen,, for de fejlagtige eksempler, men det er en god idé at gøre dette, da det sikrer, at man forstår hvilken regel man har lavet - og altså om reglen er, som man ønsker den. Bemærk at eksempler med ukorrekte sætninger skal have en  omkring den forkerte del. Det er denne del, som skal udskiftes med hvad der står i correction.

Hele reglen hører til elementet, som indeholder en regel. Den har altid et navn og et , hvor id'et bl.a. ikke må indeholde punktummer og mellemrum.

Når en enkelt regel (et enkelt ) ikke er nok til at fange alle tilfælde, kan man lave en regelgruppe,. Man skriver blot  omkring de  -elementer, som skal være en del af reglen. I så fald behøver hver enkelt regel ikke længere at have et navn og et id, kun hele regelgruppen.

I eksemplet ovenfor bruges en markør,, omkring de to  -elementer, som er indeholdt i  -elementet. bruges til at markere den eller de s, som skal ændres, og   i  -elementet beskriver denne ændring. Brug af  er ikke nødvendigt, hvis alt indeholdt i   er en fejl og skal ændres. Derfor behøver ovenstående eksempel ikke en. Det er dog en god idé at bruge  hver gang, da manglende   ofte er udgangspunkt for fejl. Derudover er det kun indholdet i, der får streg under.

-elementet i ovenstående eksempel er meget simpelt, da det giver en statisk ændring ved alle fejl ('ekskl.'). Det er dog ofte tilfældet, at ændringen er dynamisk, afhængig af fejlen. Det ses bl.a. i dette eksempel:

 ,     ,        Mangler opremsningskomma; \5, \6 https://wiki.documentfoundation.org/DA/LanguageTool/Regler#Opremsningskomma Muligvis manglende opremsningskomma En abe, ymer, løve drage og kano. Kage, krymmel, ymer og ko.

Denne regel tjekker på en sætningsdel med en struktur lig denne: "substantiv, substantiv, substantiv substantiv", hvor alle substantiver er i nominativ. I den situation mangler der formentlig et komma mellem de to sidste substantiver, da det nok er en opremsning. Derfor refererer -elementet til disse to substantiver med "\" efterfulgt af nummeret på hver enkelt af de pågældende  -elementer, altså   og , med det manglende komma imellem dem. Altså " ".

-elementer nummereres fra 1 (ikke 0) fra toppen af. Bemærk her, at  kun er omkring de sidste to substantiver, som mangler et komma imellem sig. Derfor refereres der kun til disse to i  og ikke til hele sætningsdelen.

Ovenstående regel er mere kompliceret end den forrige, idet den både bruger regulære udtryk, tags (ordtyper) og s (undtagelser).

Alle ordtyper er beskrevet i ../resource/da/danish_tags.txt; bemærk dog at ord kan mangle tags, så tjek altid ords tags, når du vil bruge dem i -elementerne.

Tokens kan være både tags (ordtyper) og konkrete ord. Tags skrives som attributter på et -element (for eksempel  ), mens ord skrives som indholdet af et  -element (altså mellem start- og slut-tagget; for eksempel  ).

Regulære udtryk kan bruges på både tags og konkrete ord, men dette skal markeres med henholdsvis  og.

s er undtagelser, som beskriver hvornår et  ikke kan bruges. I ovenstående eksempel fanges substantiver i nominativ bøjning, men kun hvis ordet ikke har andre tags end dette. Bemærk at  her er negeret, dvs. at den fanger alle bortset fra de beskrevne tags.

REGULÆRE UDTRYK
Her er et eksempel på et regulært udtryk på en  bestemt ud fra bogstaver, ikke tags:

årig(|t)|års-(.*)|tallet

regexp="yes" sætter token til at være et regulært udtryk på indholdet af denne. Her fanges 'årig', 'årigt', 'års-[her kan stå en sekvens af vilkårlige bogstaver og cifre]' og 'tallet'. Tegnet  betyder "eller" og parenteser grupperer, hvorfor   matcher både 'årig' og 'årigt'.

Et andet eksempel på et regulært udtryk er:

([0-9]|\.)+

Dette fanger alle sekvenser af cifre fra 0 til 9 samt punktummer; f.eks. '.2213.4..00'. Parentesen grupperer, at der enten skal stå et ciffer mellem 0 og 9 eller et punktum (husk at escape det med ), mens + efter parentesen bestemmer at der skal være 1 eller flere af det der står i parentesen. En kortere version, som gør præcis det samme, er denne:

[0-9.]+

Bemærk at punktummet ikke skal escapes, når det står inde i en []-parentes.

Her er et eksempel på en token, som bruger et regulært udtryk til at fange ord med bestemte tags:



sætter token til at være et regulært udtryk på tags. er de tags, som skal fanges. Her er  et substantiv i ubestemt og nominativ form, men hvor alle andre bøjninger er accepterede. Substantiver på dansk beskrives på denne struktur:, hvor hver bøjning har en tilsvarende modsætning - læs mere i. Alle andre tags følger samme struktur med kolon imellem hver bøjning. Ved at skrive  mellem eller efter et kolon fanges alle muligheder; så ovenstående eksempel fanger alle substantiver i ubestemt og nominativ form samt alle verber.

Man kan refferere til dele af et regulært udtryk i :

(en|et|to|tre|fire|fem|seks|syv|otte|ni|ti|elleve|tolv|tretten|fjorten|femten|seksten|sytten|atten|nitten|tyve|tredive|tredve|fyrre|halvtreds|tres|halvfjers|firs|halvfems|hundred(|e)|tusind(|e|er)|million(|er)|milliard(|er)) (hundred(|e)|tusind(|e|er)|million(|er)|milliard(|er)) Talord over hundrede skrives i flere ord:  .

match giver mulighed for, via et regulært udtryk, at matche på en del af den sætning, som er fanget af pattern. Her matches på token nummer 1 (den første, her eneste token), og et regulært udtryk beskriver derpå, hvordan denne skal matches. Dette regulære udtryk kunne være ens med det regulære udtryk i pattern, men kan også være anderledes, som her. Ved at lave et nyt regulært udtryk oven på et pattern, som har en fejl, kan man lave dynamiske suggestions. regexp_replace refferere til regexp_match, ikke pattern-delen, og her kan man refferere til hele sætningen med $0, og ellers er hver parantes et nummer for sig, stigende fra det første. I dette eksempel er '(?iu)' blot, at det første foreslåede ord skal være med stort eller lille afhængig af hvad ordet, der fanges, er.

Derpå bliver det regulære udtryk kørt igennem fra venstre mod højre, hvor mønsteret bliver matchet mod det første token. Hvis der stadig er flere tokens tilbage (det er der ikke i dette tilfælde, men det kunne der være, se eksempler i grammar.xml), vil det næste token blive matchet på ny på det regulære udtryk og det resulterende forslag vil blive alle tokensne, der har matchet positivt på det regulære udtryk. Hvis et token ikke matcher, vil det blive udeladt fra resultatet.

Se evt. pattern.xsd og rules.xsd for syntaks. Se test-kapitlet for testmetoder.

Links:
 * http://www.languagetool.org/development
 * DA/LanguageTool/Regler
 * http://www.languagetool.wikidot.com/tips-and-tricks
 * http://www.regular-expressions.info

Sætningsopdeler
Dette dokument skal du sandsynligvis ikke redigere i, men hvis du gør: vær ekstra opmærksom på at teste grammatikkontrollen, da det kan påvirke tidligere regler.

Dokumentet ligger i ../resource/segment.srx og er også skrevet i xml og bruger regulære udtryk samt unicode; se mere om unicode her: http://www.regular-expressions.info/unicode.html. Dokumentet indeholder alle sprogs sætningsopdeler, så for at finde den danske del kan du søge på '', som indikere starten på den danske del.

En regel her er at ellipsis (to og tre punktummer efter hinanden) ikke nødvendigvis indikere slutningen på en sætning; kun hvis det første efterfølgende bogstav er stort.

Ratel er et super godt værktøj til at teste sætningsopdeleren. Indlæs (open) blot segment.srx og vælg det danske sprog, vælgt evt. specifikke regler (fra segment.srx) til og fra, og skriv da sætninger i tekstboksen, hvorved Ratel dynamisk analysere teksten og opdeler den. Ratel kan hentes her: http://www.opentag.com/okapi/wiki/index.php?title=Ratel.

Links:
 * http://languagetool.wikidot.com/customizing-sentence-segmentation-in-srx-rules
 * http://www.regular-expressions.info/unicode.html
 * http://www.regular-expressions.info
 * http://www.fileformat.info/info/unicode
 * http://www.opentag.com/okapi/wiki/index.php?title=Ratel

Flertydigheder
Med flertydighed menes, at ord kan have flere ordklasser; f.eks. er ordet 'jeg' både et substantiv og et pronomen. Det bestemmes i disambiguation.xml.

Vores disambiguator er regelbaseret ligesom bl.a. den engelske, så det er nemmere at finde dokumentation/inspiration til udvikling af den danske. Nogle sprog bruger andre metoder end denne, f.eks. en Java-baseret.

Regelbaseret disambiguation følger på mange måder strukturen af.

Her er et eksempel på en regel i :

   <token postag_regexp="yes" postag="ver:.*"/> <exception postag_regexp="yes" postag="ver:.*"/> <disambig action="filter" postag="pron:.*"/> <example type="ambiguous" inputform="Jeg[jeg/pron:sin:nom,jeg/sub:ube:sin:neu:nom]" outputform="Jeg[jeg/pron:sin:nom]"> Jeg er mig! Du kan gøre det. Dette er urørt!

Reglen tester for et ord, der både er pronomen og substantiv, og som er efterfulgt af et verbum, og kun et verbum. Hvis dette findes, fjernes substantiv-tagget, så ordet kun er markeret som et pronomen. Det gør, at regler i grammar.xml kan baseres på tags, og her, at regler, som fanger pronomener, kun fanger ord, som er defineret som pronomen. Denne regel hjælper f.eks. opremsningskomma-reglen i grammar.xml, som er baseret på substantiver, ved at fjerne potentielle falske positiver.

følger strukturen fra grammar.xml.

har forskellige actions, som bl.a. er at fjerne og tilføje tags til, hvad der er markeret i. Læs mere om actions her: http://languagetool.wikidot.com/developing-a-disambiguator.

følger strukturen fra grammar.xml. Hvis man er i tvivl om, hvilke tags et ord har, kan man bruge en kommando af denne form:

echo | java -jar LanguageTool.jar -l   -d <discard_rules> -v

hvor  viser tags på alle ord. Det samme kan bruges på test af korpus. skal være  for dansk.

Du finder dokumentet til flertydighed (disambiguation) i denne fil: languagetool-language-modules\da\src\main\resources\org\languagetool\resource\da\disambiguation.xml

Se evt. filen languagetool-core\src\main\resources\org\languagetool\resource\disambiguation.xsd

for syntaksen for.

Links:
 * http://languagetool.wikidot.com/developing-a-disambiguator

Falske venner
Når ord ligner hinanden på tværs af sprog, men har forskellig mening, kaldes de falske venner. Disse bliver fanget i false-friends.xml med xml-regler, der er lavet på samme måde, som i grammatikken grammar.xml. Man laver typisk en regelgruppe, som indeholder to regler: den korrekte danske oversættelse af det fremmede ord og den korrekte oversættelse på det fremmede sprog af det danske ord. Ordene kan være helt ens, eller blot ligge meget tæt på hinandens stavelse. Der kan være flere oversættelser, både til flere forskellige sprog, men også flere oversættelser af ordet på samme sprog, og derved skrives blot flere -tags med de forskellige sprog og deres oversættelser (som altså godt kan være samme sprog). Se evt. på de øverste regler.

Et eksempel på en dansk-svensk regel er: <rulegroup id="ROLIG"> rolig lugna rolig sjovt

Du finder dokumentet til falske venner (false-friends) her: languagetool-core/src/main/resources/org/languagetool/rules/false-friends.xml.

Links:
 * http://languagetool.wikidot.com/usage-of-false-friends-rule
 * http://sv.wikipedia.org/wiki/Lista_%C3%B6ver_falska_v%C3%A4nner/Nordiska_spr%C3%A5k

Linux
For at teste grammar.xml (grammatikreglerne), dvs. de unittests, der er skrevet i den som -elementer, skal du i terminalen (her fra  -mappen) bruge kommandoen:

sh testrules.sh  

Så når den danske udgave af grammar.xml skal testes skrives:

sh testrules.sh da

For at teste hele LanguageTool på et korpus (en tekst/tekstsamling), kan du i terminalen (antaget du har java version 1,6+) (med Languagetool-mappen som aktuel mappe) køre en kommando på formen:

java -jar LanguageTool.jar -l   -c   -t <corpus_file> > -d <discard_rules> <tagged_corpus_file>

Den kunne i praksis f.eks. se således ud:

java -jar LanguageTool.jar -l da -d WHITESPACE_RULE,UPPERCASE_SENTENCE_START,UNPAIRED_BRACKETS,DOUBLE_PUNCTUATION,\ COMMA_PARENTHESIS_WHITESPACE,HUNSPELL_NO_SUGGEST_RULE Korpus.txt

Argumenterne efter  angiver, hvad der ikke skal testes for. I ovenstående er der en del, der ikke testes for, men det er et bevidst valg, idet jeg har brugt ovenstående kommando til at teste grammatikreglerne (fra grammar.xml), og her er det f.eks. uinteressant om et ord ikke er stavet korrekt ifølge ordbogen (udeladt med ). Korpus.txt er en fil med det korpus, jeg tester på. Denne bør være omfattende, så så mange fejl i reglerne som muligt kan opfanges. Evt. kan bevidste fejl indsættes i korpuset, for at teste om reglerne fanger dem.

Derudover kan argumentet  bruges, hvis man gerne vil se, hvorledes alle ord er tagget.

Man kan også teste med en direkte tekststreng (string) i stedet for et korpus, ved i terminalen at bruge  i stedet for at angive korpuset sidst i kommandoen:

echo   | java -jar LanguageTool.jar -l   -d <discard_rules>

Det kunne f.eks. se således ud:

echo "Dette er en sætning jeg vil teste!" | java -jar LanguageTool.jar -l da -d HUNSPELL_NO_SUGGEST_RULE

Links:
 * http://languagetool.wikidot.com/tips-and-tricks

Kilder

 * Sproget.dk: Latinske sprogbetegnelser