~/home of geeks

Namensmajuskel

· 528 Wörter · 3 Minute(n) Lesedauer

In einer zu verarbeitenden Datei standen Personennamen in Minuskeln, wie z. B. “hans-peter von groß”. Gewünscht war, diese in richtiger Schreibweise, also mit Majusklen, wie “Hans-Peter von Groß” zu haben.

Was sich zuerst einfach anhört, hat bei genauerer Betrachtung mehrere Problemfälle. Mein initialer Ansatz machte aus allen Anfangsbuchstaben, also solchen, die einem Leerzeichen oder einem Sonderzeichen (z. B. “-” oder “.”) folgen, einen Großbuchstaben.

public static final String capitalize(final String s) {
    if (s == null || s.trim().length() == 0) {
        return s;
    }
    
    // Macht das erste Zeichen nach einem Leerzeichen oder Sonderzeichen zu einem Majuskel
    boolean lastSpecial = true;
    char lastSpecialValue = '\\00';
    final StringBuilder result = new StringBuilder();
    for (final char c : s.toCharArray()) {
        if (Character.isLetter(c)) {
            if (lastSpecial) {
                result.append(Character.toUpperCase(c));
            } else {
                result.append(Character.toLowerCase(c));
            }
            lastSpecialValue = '\\00';
            lastSpecial = false;
        } else {
            // Ignoriert doppelte Sonderzeichen, wie zwei aufeinander folgende Leerzeichen
            if (lastSpecialValue != c) {
                result.append(c);
            }
            lastSpecialValue = c;
            lastSpecial = true;
        }
    }
    
    return result.toString();
}

Soweit funktionierte dies gut, wenn da nicht diese Ausnahmen wären. So werden viele Namenszusätze, wie “von”, “van” oder “da”, kleingeschrieben verwendet. Dann gibt es noch Namenszusätze, die gemischte Schreibweisen haben, wie “MdB”. Alle diese Fälle (ok, in Wirklichkeit nur eine für mich ausreichende Untermenge) habe ich dann anschließend erfasst und als Sonderregeln angewendet.

import java.util.regex.Pattern;

public class NamensMajuskel {

    public static void main(final String[] args) {
        final String[] tests = new String[] { 
            "hans-peter von groß", "hans peter van man-groß", 
            "hans peter van o' hara", "h.p. dieter", 
            "thomas van der laach", "leonardo da vinci",
            "prof. dr. mdb nachtigaller"
        };

        for (final String name : tests) {
            System.out.println(name + " -> " + capitalize(name));
        }
    }

    private static final String[] NAMENSZUSÄTZE = new String[] { "von", "ten", "van't", "van der", "van", "de la", "de l'", "de", "du", "di", "del", "dello",
        "della", "dei", "delle", "da", "dal", "MdB" };
    
    private static final Pattern[] PATTERNS_NAMENSZUSÄTZE = new Pattern[NAMENSZUSÄTZE.length];
    static{
        for (int i=0; i<NAMENSZUSÄTZE.length; i++){
            PATTERNS_NAMENSZUSÄTZE[i] = Pattern.compile("\\\\Q" + NAMENSZUSÄTZE[i] + "\\\\E", Pattern.CASE_INSENSITIVE);
        }
    }
    
    public static final String capitalize(final String s) {
        if (s == null || s.trim().length() == 0) {
            return s;
        }
        
        // Macht das erste Zeichen nach einem Leerzeichen oder Sonderzeichen zu einer Majuskel
        boolean lastSpecial = true;
        char lastSpecialValue = '\\00';
        final StringBuilder result = new StringBuilder();
        for (final char c : s.toCharArray()) {
            if (Character.isLetter(c)) {
                if (lastSpecial) {
                    result.append(Character.toUpperCase(c));
                } else {
                    result.append(Character.toLowerCase(c));
                }
                lastSpecialValue = '\\00';
                lastSpecial = false;
            } else {
                // Ignoriert doppelte Sonderzeichen, wie zwei aufeinander folgende Leerzeichen
                if (lastSpecialValue != c) {
                    result.append(c);
                }
                lastSpecialValue = c;
                lastSpecial = true;
            }
        }

        // Rückersetzen aller besonderen Namenszusätze
        String resultStr = result.toString();
        for (int i=0; i<PATTERNS_NAMENSZUSÄTZE.length; i++){
            final Pattern patternNamensZusatz = PATTERNS_NAMENSZUSÄTZE[i];
            resultStr = patternNamensZusatz.matcher(resultStr).replaceFirst(NAMENSZUSÄTZE[i]);
        }
        return resultStr;
    }
}

Ich gebe zu, dass das Ersetzen per regulärer Ausdrücke nicht so elegant geworden ist (Laufzeit). Bei mehr Umsetzungszeit hätte ich die Eingaben in Token zerlegt, diese einzeln verarbeitet und dabei dann auch bestimmt, ob ein Token mit großem Anfangsbuchstaben versehen werden muss oder nicht.

Erwähnt werden sollte, dass es auch Fälle gibt, die nicht eindeutig sind. So kann der Nachname “O’Hara” manchmal als “O’hara” geschrieben werden.