Lexikografisch sortieren (Algorithmen)
Um eine lexikographische Ordnung von Wörtern zu erreichen, kann nicht einfach die triviale aufsteigende Sortierung einer Zeichentabelle durchgeführt werden.
Zum einen müssen große und kleine Buchstaben gleich behandelt werden, und zum anderen sollen Umlaute und Ligaturen (ß) nach ihren zugrunde liegenden Buchstaben einsortiert werden:
A < a < AA < aa < AAb < Aachen < ...
... < aha < Ähre < Akne < ...
... < haschen < Häschen < hat < ...
... < Masse < Maße < Maßeinheit < ...
... < ZZ < zz
Entwickeln Sie nach obigem Beispiel eine Funktion, die zwei gegebene Wörter miteinander vergleicht.
Tipp: Ein 'ä' wird wie ein 'a' sortiert, es sei denn, es gibt auch eine ansonsten identische Wortvariante mit einem 'a' an derselben Stelle. In einem solchen Fall wird das Wort mit Umlaut nach letzterem einsortiert. Analog verhält es sich mit den Groß- und Kleinbuchstaben. Mit Vorteil werden die Wörter zunächst in ihre lexikalische Grundform gebracht: nur Kleinbuchstaben, keine Umlaute [a statt ä], keine Ligaturen [ss statt ß], keine Satzzeichen [Leerschlag statt '.']. Stimmen die Grundformen nicht überein, so wird nach eben dieser Grundform sortiert.
Dateien:
2 Kommentare
4 Lösung(en)
import java.util.Comparator;
/**
* Sortiere Deutsch.
* @author Philipp Gressly (phi AT gressly DOT ch)
*/
public class DeutscherLexer implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
String ersetzt1 = ersetze(s1);
String ersetzt2 = ersetze(s2);
int cmp = ersetzt1.compareTo(ersetzt2);
if(0 != cmp) {
return cmp; }
for(int i = 0; i < s1.toLowerCase().length(); i++) {
char c1 = s1.toLowerCase().charAt(i);
char c2 = s2.toLowerCase().charAt(i);
if(c1 != c2) {
return compareChars(c1, c2);
}
}
for(int i = 0; i < s1.length(); i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if(c1 != c2) {
return compareChars(c1, c2);
}
}
return 0; }
int compareChars(char c1, char c2) {
if(istZiffer(c1) && istZiffer(c2) ) {
return c1 - c2; }
if(isSpecial(c1) && isSpecial(c2) ) {
return c1 - c2; }
if(isUpperCase(c1) && isUpperCase(c2)) {
return c1 - c2; }
if(isLowerCase(c1) && isLowerCase(c2)) {
return c1 - c2; }
int t1 = typeOf(c1); // 1: upper, 2: lower, 3: special
int t2 = typeOf(c2);
return t1 - t2; }
boolean istZiffer(char c2) {
return '0' <= c2 && c2 <= '9'; }
/**
* Zum Sortieren der Typen lowerCase, upperCase, special
* @return 1: upper; 2: lower; 3: special; 4: ziffer
*/
int typeOf(char c1) {
if(isUpperCase(c1)) {
return 1; }
if(isLowerCase(c1)) {
return 2; }
if(istZiffer(c1)) {
return 4;
}
return 3; } // special = 3
boolean isSpecial(char c) {
return !isLowerCase(c) && !isUpperCase(c); }
boolean isUpperCase(char c) {
return 'A' <= c && c <= 'Z'; }
boolean isLowerCase(char c) {
return 'a' <= c && c <= 'z'; }
/**
* Ersetze Sonderzeichen durch ihre Grundbuchstaben.
* Z. B. wird aus "Häuschen" "Hauschen" und aus
* "Maße" wird "Masse".
*/
String ersetze(String original) {
StringBuilder sb = new StringBuilder();
for(char c : original.toCharArray()) {
c = Character.toLowerCase(c);
if('ä' == c) {
sb.append("a"); }
else if('ö' == c) {
sb.append("o"); }
else if('ü' == c) {
sb.append("u"); }
else if('ß' == c) {
sb.append("ss"); }
else if(Character.isLetter(c)) {
sb.append(c); }
else if(istZiffer(c)) {
sb.append(c);
}
}
return sb.toString();
}
} // end of class DeutscherLexer
# Lexikallische Sortierung
# 1. Schritt alle Worte werden in eindeutige Kleinschreibweise formatiert
# 2. Aufbau einer Schlüssel --> Werte Struktur (assoziatives Array)
# Die Schlüssel sind die Worte in eindeutiger Kleinschreibweise
# Die Werte sind die original Worte
# 3. Schritt Sortieren der Schlüssel und dann Ausgabe der Werte
def eindeutigeSchreibweise(s):
s1 = s.lower()
s2 = ''
for c in s1:
if c == 'ä':
s2 = s2 + 'a'
else:
if c == 'ö':
s2 = s2 + 'o'
else:
if c == 'ü':
s2 = s2 + 'u'
else:
if c == 'ß':
s2 = s2 + 'ss'
else:
s2 = s2 + c
return s2
def lexikalSortieren(l):
#Aufbau des assoziativen Array (dictionary)
woerter ={}
for w in l:
s = eindeutigeSchreibweise(w)
woerter[s]=w
wlist = woerter.keys()
wlist.sort()
for wort in wlist:
print woerter[wort]
s = 'Häschen hat Masse A a so macht das kein Sinn Maßeinheit ZZ Top AA aa AAb Aachen aha Ähre Akne haschen Maße '
l = s.split()
lexikalSortieren(l)
Lösung von: Martin Guggisberg (Universität Basel / PH FHNW)
/*****************************************************************************\
| In JavaScript wäre das die einfache anweisung
>>>>
> Array.sort(String1.localeCompare(String2));
>>>>
| respektive:
>>>>
> Array.sort(String1.localeCompare(String2, "de",
> {sensitivity: case, ignorePunctuation: true, caseFirst: upper }));
>>>>
| um die deutsche lexikographie zu erzwingen.
| Hier aber die harte tour.
\*****************************************************************************/
function compareLemmas_de(lem1, lem2) {
var comp1, comp2,
i = 0;
function prepare(str) {
str = str.toLowerCase(); // kleinbuchstaben
str = str.replace(/ä/g, "a");
str = str.replace(/ö/g, "o");
str = str.replace(/ü/g, "u");
str = str.replace(/ß/g, "s");
str = str.replace(/(\.)|( )|(-)/g, ""); // punkt, leerzeichen, bindestrich
return str;
}
function isUpperCase(char) { return char == char.toLowerCase(); }
function isSpecialChar(char) {
return char == "Ä" || "ä" || "Ö" || "ö" || "Ü" || "ü" || "ß";
}
var comp1 = prepare(lem1), comp2 = prepare(lem2);
if (comp1 > comp2) return 1;
if (comp1 < comp2) return -1;
if (comp1 == comp2) {
while(i < Math.min(lem1.length, lem2.length)) {
if (
(isUpperCase(lem1[i]) && !isUpperCase(lem2[i])) || // A > a
(isSpecialChar(lem1[i]) && !isSpecialChar(lem2[i])) // a > ä
) return 1;
else if (
(!isUpperCase(lem1[i]) && isUpperCase(lem2[i])) || // a < A
(!isSpecialChar(lem1[i]) && isSpecialChar(lem2[i])) // ä < a
) return -1;
i++;
}
// nach der while-schleife: das längere wort wird nachsortiert
if (lem1.length > lem2.length) return -1;
else if (lem1.length < lem2.length) return 1;
// und schließlich:
return 0; // falls keine unterscheidung zwischen A/a oder a/ä möglich
}
}
var wordList = ("A,hat,Masse,A.A.,AAA,Achter,Häschen,Aal,hält,Menschenskind," +
"AAb,RE44,Ähre,RE - 44,re,re44,massieren,A. Hauser,RE43,RE - 43,re43,Akne," +
"H. Aschen,Masseur,Ahoi,RE34,RE - 34,re34,Weinflasche,Aachen,achter,Mist," +
"a,Maß,aha,AA,ZZ,haschen,zz,Maßeinheit,aa").split(",");
wordlist.sort(compareLemmas_de);
document.write(wordList.join(" > ")); // lissalanda@gmx.at
Lösung von: Lisa Salander (Heidi-Klum-Gymnasium Bottrop)
public class Main {
public static void main(String[] args) {
List<String> words = new ArrayList<>();
words.add("A");
words.add("hat");
words.add("Masse");
words.add("A.A.");
words.add("AAA");
words.add("Achter");
words.add("Häschen");
words.add("Aal");
words.add("hält");
words.add("Menschenskind");
words.add("AAb");
words.add("RE44");
words.add("Ähre");
words.add("RE - 44");
words.add("re");
words.add("re44");
words.add("massieren");
words.add("A. Hauserv");
words.add("RE43");
words.add("RE - 43");
words.add("re43");
words.add("Akne");
words.add("H. Aschen");
words.add("Masseur");
words.add("Ahoi");
words.add("RE34");
words.add("RE - 34");
words.add("re34");
words.add("Weinflasche");
words.add("Aachen");
words.add("achter");
words.add("Mist");
words.add("a");
words.add("Maß (und no a Maß)");
words.add("aha");
words.add("AA");
words.add("ZZ");
words.add("haschen");
words.add("zz");
words.add("Maßeinheit");
words.add("aa");
new Main().sort(words);
}
private void sort(List<String> words) {
words.sort(new Sort());
words.forEach(System.out::println);
}
private static class Sort implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
s1 = init(s1);
s2 = init(s2);
for(char c1 : s1.toCharArray()) {
for(char c2 : s2.toCharArray()) {
if(c1 < c2) {
return -1;
} else if(c1 > c2) {
return 1;
}
}
}
return 0;
}
private String init(String s) {
return s.toLowerCase().replace("ä", "a")
.replace("ö", "o")
.replace("ü", "u")
.replace("ß", "ss")
.replace(".", "")
.replace("-", "");
}
}
}
Lösung von: Name nicht veröffentlicht
Verifikation/Checksumme:
Beispiele von Grundformen:
- Schweiz -> schweiz
- für -> fur
- Öl -> ol
- Maße -> masse
Aktionen
Neue Lösung hinzufügen
Bewertung
Durchschnittliche Bewertung:
Meta
Zeit: | 2-4 |
Schwierigkeit: | k.A. |
Webcode: | t42p-7sny |
Autor: | Philipp G. Freimann (BBW (Berufsbildungsschule Winterthur) https://www.bbw.ch) |
Kommentare (2)
Der "deutsche Lexer" ist ein Beispiel eines Java-Comparators.
Er wird eingesetzt bei allen sort()- und search()-Funktionen, die als Argument einen Comparator verlangen.
Beispiele:
Arrays.binarySearch(array, from, to, comparator)
Arrays.sort(array, from, to, comparator)