/* LanguageTool, a natural language style checker
* Copyright (C) 2015 Daniel Naber (http://www.danielnaber.de)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package org.languagetool.chunking;
import org.junit.Test;
import org.languagetool.AnalyzedSentence;
import org.languagetool.AnalyzedTokenReadings;
import org.languagetool.JLanguageTool;
import org.languagetool.language.German;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.fail;
public class GermanChunkerTest {
private final JLanguageTool lt = new JLanguageTool(new German());
private final GermanChunker chunker = new GermanChunker();
@Test
public void testChunking() throws Exception {
assertFullChunks("Ein/B Haus/I");
assertFullChunks("Ein/NPP Hund/NPP und/NPP eine/NPP Katze/NPP stehen dort");
assertFullChunks("Es war die/NPS größte/NPS und/NPS erfolgreichste/NPS Erfindung/NPS");
assertFullChunks("Geräte/B , deren/NPS Bestimmung/NPS und/NPS Funktion/NPS unklar sind.");
assertFullChunks("Julia/NPP und/NPP Karsten/NPP sind alt");
assertFullChunks("Es ist die/NPS älteste/NPS und/NPS bekannteste/NPS Maßnahme/NPS");
assertFullChunks("Das ist eine/NPS Masseeinheit/NPS und/NPS keine/NPS Gewichtseinheit/NPS");
assertFullChunks("Sie fährt nur eins/NPS ihrer/NPS drei/NPS Autos/NPS");
assertFullChunks("Da sind er/NPP und/NPP seine/NPP Schwester/NPP");
//assertFullChunks("Sowohl/NPP sein/NPP Vater/NPP als/NPP auch/NPP seine/NPP Mutter/NPP sind da"); //?
//assertFullChunks("Sowohl/NPP Tom/NPP als/NPP auch/NPP Maria/NPP sind da");
//assertFullChunks("Sowohl/NPP er/NPP als/NPP auch/NPP seine/NPP Schwester/NPP sind da");
assertFullChunks("Rekonstruktionen/NPP oder/NPP der/NPP Wiederaufbau/NPP sind das/NPS Ziel/NPS");
assertFullChunks("Isolation/NPP und/NPP ihre/NPP Überwindung/NPP ist das/NPS Thema/NPS");
assertFullChunks("Es gibt weder/NPP Gerechtigkeit/NPP noch/NPP Freiheit/NPP");
assertFullChunks("Da sitzen drei/NPP Katzen/NPP");
assertFullChunks("Der/NPS von/NPS der/NPS Regierung/NPS geprüfte/NPS Hund/NPS ist grün");
assertFullChunks("Herr/NPP und/NPP Frau/NPP Schröder/NPP sind betrunken");
//assertFullChunks("Die/NPS hohe/NPS Zahl/NPS dieser/NPS relativ/NPS kleinen/NPS Verwaltungseinheiten/NPS ist beeindruckend"); //?
//assertFullChunks("Das ist eine/NPS der/NPS am/NPS meisten/NPS verbreiteten/NPS Krankheiten/NPS"); //?
assertFullChunks("Das sind 37/NPS Prozent/NPS");
assertFullChunks("Das sind 37/NPP Prozent/NPP");
assertFullChunks("Er will die/NPP Arbeitsplätze/NPP so umgestalten , dass/NPP sie/NPP wie/NPP ein/NPP Spiel/NPP sind.");
assertFullChunks("So dass Knochenbrüche/NPP und/NPP Platzwunden/NPP die/NPP Regel/NPP sind");
assertFullChunks("Eine/NPS Veranstaltung/NPS ,/NPS die/NPS immer/NPS wieder/NPS ein/NPS kultureller/NPS Höhepunkt/NPS war");
assertFullChunks("Und die/NPS ältere/NPS der/NPS beiden/NPS Töchter/NPS ist 20.");
assertFullChunks("Der/NPS Synthese/NPS organischer/NPS Verbindungen/NPS steht nichts im/PP Weg/NPS");
assertFullChunks("Aber/B die/NPP Kenntnisse/NPP der/NPP Sprache/NPP sind nötig."); // actually "Aber" should not be tagged
assertFullChunks("Dort steht die/NPS Pyramide/NPS des/NPS Friedens/NPS und/NPS der/NPS Eintracht/NPS");
assertFullChunks("Und Teil/B der/NPS dort/NPS ausgestellten/NPS Bestände/NPS wurde privat finanziert.");
assertFullChunks("Autor/NPS der/NPS ersten/NPS beiden/NPS Bücher/NPS ist Stephen King/NPS");
assertFullChunks("Autor/NPS der/NPS beiden/NPS Bücher/NPS ist Stephen King/NPS");
assertFullChunks("Teil/NPS der/NPS umfangreichen/NPS dort/NPS ausgestellten/NPS Bestände/NPS stammt von privat");
assertFullChunks("Ein/NPS Teil/NPS der/NPS umfangreichen/NPS dort/NPS ausgestellten/NPS Bestände/NPS stammt von privat");
assertFullChunks("Die/NPS Krankheit/NPS unserer/NPS heutigen/NPS Städte/NPS und/NPS Siedlungen/NPS ist der/NPS Verkehr/NPS");
assertFullChunks("Der/B Nil/I ist der/NPS letzte/NPS der/NPS vier/NPS großen/NPS Flüsse/NPS");
assertFullChunks("Der/NPS letzte/NPS der/NPS vier/NPS großen/NPS Flüsse/NPS ist der/B Nil/I");
assertFullChunks("Sie kennt eine/NPP Menge/NPP englischer/NPP Wörter/NPP");
assertFullChunks("Eine/NPP Menge/NPP englischer/NPP Wörter/NPP sind aus/PP dem/NPS Lateinischen/NPS abgeleitet.");
assertFullChunks("Laut/PP den/PP meisten/PP Quellen/PP ist er 35 Jahre/B alt.");
assertFullChunks("Bei/PP den/PP sehr/PP niedrigen/PP Oberflächentemperaturen/PP verbrennt nichts");
assertFullChunks("In/PP den/PP alten/PP Religionen/PP ,/PP Mythen/PP und/PP Sagen/PP tauchen Geister/B auf.");
assertFullChunks("Die/B Straße/I ist wichtig für/PP die/PP Stadtteile/PP und/PP selbständigen/PP Ortsteile/PP");
assertFullChunks("Es herrscht gute/NPS Laune/NPS in/PP chemischen/PP Komplexverbindungen/PP");
assertFullChunks("Funktionen/NPP des/NPP Körpers/NPP einschließlich/PP der/PP biologischen/PP und/PP sozialen/PP Grundlagen/PP");
assertFullChunks("Das/NPS Dokument/NPS umfasst das für/PP Ärzte/PP und/PP Ärztinnen/PP festgestellte/PP Risikoprofil/PP");
assertFullChunks("In/PP den/PP darauf/PP folgenden/PP Wochen/PP ging es los.");
assertFullChunks("In/PP nur/PP zwei/PP Wochen/PP geht es los.");
assertFullChunks("Programme/B , in/PP deren/PP deutschen/PP Installationen/PP nichts funktioniert.");
assertFullChunks("Nach/PP sachlichen/PP und/PP militärischen/PP Kriterien/PP war das unnötig.");
assertFullChunks("Mit/PP über/PP 1000/PP Handschriften/PP ist es die/NPS größte/NPS Sammlung/NPS");
assertFullChunks("Es gab Beschwerden/NPP über/PP laufende/PP Sanierungsmaßnahmen/PP");
assertFullChunks("Gesteigerte/B Effizienz/I durch/PP Einsatz/PP größerer/PP Maschinen/PP und/PP bessere/PP Kapazitätsplanung/PP");
assertFullChunks("Bei/PP sehr/PP guten/PP Beobachtungsbedingungen/PP bin ich dabei");
assertFullChunks("Die/NPP Beziehungen/NPP zwischen/NPP Kanada/NPP und/NPP dem/NPP Iran/NPP sind unterkühlt");
assertFullChunks("Die/PP darauffolgenden/PP Jahre/PP war es kalt");
assertFullChunks("Die/NPP darauffolgenden/NPP Jahre/NPP waren kalt");
assertFullChunks("Die/PP letzten/PP zwei/PP Monate/PP war es kalt");
//assertFullChunks("Die/NPP letzten/NPP zwei/NPP Monate/NPP waren kalt");
assertFullChunks("Letztes/PP Jahr/PP war kalt");
assertFullChunks("Letztes/PP Jahr/PP war es kalt");
assertFullChunks("Es sind Atome/NPP ,/NPP welche/NPP der/NPP Urstoff/NPP aller/NPP Körper/NPP sind");
assertFullChunks("Kommentare/NPP ,/NPP Korrekturen/NPP ,/NPP Kritik/NPP bitte nach /dev/null");
assertFullChunks("Einer/NPS der/NPS beiden/NPS Höfe/NPS war schön");
}
// B = begin, will be expanded to B-NP, I = inner, will be expanded to I-NP
@Test
public void testOpenNLPLikeChunking() throws Exception {
//GermanChunker.setDebug(true);
assertBasicChunks("Ein/B Haus/I");
assertBasicChunks("Da steht ein/B Haus/I");
assertBasicChunks("Da steht ein/B schönes/I Haus/I");
assertBasicChunks("Da steht ein/B schönes/I großes/I Haus/I");
assertBasicChunks("Da steht ein/B sehr/I großes/I Haus/I");
assertBasicChunks("Da steht ein/B sehr/I schönes/I großes/I Haus/I");
assertBasicChunks("Da steht ein/B sehr/I großes/I Haus/I mit Dach/B");
assertBasicChunks("Da steht ein/B sehr/I großes/I Haus/I mit einem/B blauen/I Dach/I");
assertBasicChunks("Eine/B leckere/I Lasagne/I");
assertBasicChunks("Herr/B Meier/I isst eine/B leckere/I Lasagne/I");
assertBasicChunks("Herr/B Schrödinger/I isst einen/B Kuchen/I");
assertBasicChunks("Herr/B Schrödinger/I isst einen/B leckeren/I Kuchen/I");
assertBasicChunks("Herr/B Karl/I Meier/I isst eine/B leckere/I Lasagne/I");
assertBasicChunks("Herr/B Finn/I Westerwalbesloh/I isst eine/B leckere/I Lasagne/I");
assertBasicChunks("Unsere/B schöne/I Heimat/I geht den/B Bach/I runter");
assertBasicChunks("Er meint das/B Haus/I am grünen/B Hang/I");
assertBasicChunks("Ich/B muss dem/B Hund/I Futter/I geben"); // TODO: see next line for how it should be (but: 'Pariser Innenstadt' should be one NP)
//assertChunks("Ich muss dem/B Hund/I Futter/B geben");
assertBasicChunks("Das/B Wasser/I , das die/B Wärme/I überträgt");
assertBasicChunks("Er mag das/B Wasser/I , das/B Meer/I und die/B Luft/I");
assertBasicChunks("Schon mehr als zwanzig/B Prozent/I der/B Arbeiter/I sind im Streik/B");
assertBasicChunks("Das/B neue/I Gesetz/I betrifft 1000 Bürger/B"); // '1000' sollte evtl. mit in die NP...
assertBasicChunks("In zwei/B Wochen/I ist Weihnachten/B");
assertBasicChunks("Eines ihrer/B drei/I Autos/I ist blau");
}
@Test
public void testTemp() throws Exception {
//GermanChunker.setDebug(true);
//TODO:
//assertFullChunks("Seine Novelle, die eigentlich eine Glosse ist, war so.");
//assertChunks("Das/B Wasser/I , das Wärme/B überträgt"); // keine Kongruenz bzgl. Genus -> keine NP
//assertChunks("Das/B Wasser/I , das viel/B Wärme/I überträgt"); // keine Kongruenz bzgl. Genus -> keine NP
//assertChunks("Das/B Wasser/I , das wohlige/B Wärme/I überträgt"); // keine Kongruenz bzgl. Genus -> keine NP
// das bereits erreichte Ergebnis
// die privat Krankenversicherten
// die auf ihre Tochter stolze Frau
// jemand Schönes
// fast eine Millionen Studenten
// nahezu alle Studenten
// rund 40 Gäste
// über 20 Besucher
// der fleißige Dr. Christoph Schmidt
// der Hund von Peter
// Peters Hund
// ein Mann mit einem Radio in der Nase
// die Hoffnung auf ein baldiges Ende
}
private void assertBasicChunks(String input) throws Exception {
String plainInput = getPlainInput(input);
AnalyzedSentence analyzedSentence = lt.getAnalyzedSentence(plainInput);
AnalyzedTokenReadings[] result = analyzedSentence.getTokensWithoutWhitespace();
List<ChunkTaggedToken> basicChunks = chunker.getBasicChunks(Arrays.asList(result));
List<String> expectedChunks = getExpectedChunks(input);
assertChunks(input, plainInput, basicChunks, expectedChunks);
}
private void assertFullChunks(String input) throws Exception {
String plainInput = getPlainInput(input);
AnalyzedSentence analyzedSentence = lt.getAnalyzedSentence(plainInput);
AnalyzedTokenReadings[] result = analyzedSentence.getTokensWithoutWhitespace();
chunker.addChunkTags(Arrays.asList(result));
List<String> expectedChunks = getExpectedChunks(input);
List<ChunkTaggedToken> result2 = new ArrayList<>();
int i = 0;
for (AnalyzedTokenReadings readings : result) {
if (i > 0) {
ChunkTaggedToken chunkTaggedToken = new ChunkTaggedToken(readings.getToken(), readings.getChunkTags(), readings);
result2.add(chunkTaggedToken);
}
i++;
}
assertChunks(input, plainInput, result2, expectedChunks);
}
private String getPlainInput(String input) {
return input.replaceAll("/[A-Z-]*", "").replace(" ,", ",");
}
private List<String> getExpectedChunks(String input) {
List<String> expectedChunks = new ArrayList<>();
String[] parts = input.split(" ");
for (String part : parts) {
String[] tokenParts = part.split("/");
if (tokenParts.length == 2) {
String chunk = tokenParts[1];
if (chunk.equals("B")) {
expectedChunks.add("B-NP");
} else if (chunk.equals("I")) {
expectedChunks.add("I-NP");
} else if (chunk.equals("NPP")) {
expectedChunks.add("NPP");
} else if (chunk.equals("NPS")) {
expectedChunks.add("NPS");
} else if (chunk.equals("PP")) {
expectedChunks.add("PP");
} else {
throw new RuntimeException("Unknown chunk type: '" + chunk + "'");
}
} else {
expectedChunks.add("O");
}
}
return expectedChunks;
}
private void assertChunks(String input, String plainInput, List<ChunkTaggedToken> chunks, List<String> expectedChunks) {
int i = 0;
for (String expectedChunk : expectedChunks) {
ChunkTaggedToken outputChunksHere = chunks.get(i);
if (!outputChunksHere.getChunkTags().contains(new ChunkTag(expectedChunk))) {
fail("Expected '" + expectedChunk + "' but got '" + outputChunksHere + "' at position " + i + " for input:\n " + input +
"\nPlain input:\n " + plainInput +
"\nChunks:\n " + chunks +
"\nExpected:\n " + expectedChunks);
}
i++;
}
}
}