Подтвердить что ты не робот

Библиотека анализа имени Java?

Я ищу библиотеку, похожую на функциональность, на модуль Perl Lingua:: EN:: NameParse. По сути, я бы хотел разобрать строки, такие как "Mr. Bob R. Smith 'в префикс, имя, фамилию и суффикс имени. Google не очень помог найти что-то подобное, и я бы предпочел не сворачивать, если это возможно, самостоятельно. Кто-нибудь знает библиотеку OSS Java, которая может сделать это сложным способом?

4b9b3361

Ответ 1

Я просто не могу поверить, что кто-то не поделился библиотекой для этого - ну, я посмотрел в github и там был парсер javascript, который можно было легко перевести в java: https://github.com/joshfraser/JavaScript-Name-Parser

Я также модифицировал код в одном из ответов, чтобы немного поработать и включил тестовый пример:

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

public class NameParser {
    private String firstName = "";
    private String lastName = "";
    private String middleName = "";
    private List<String> middleNames = new ArrayList<String>();
    private List<String> titlesBefore = new ArrayList<String>();
    private List<String> titlesAfter = new ArrayList<String>();
    private String[] prefixes = { "dr", "mr", "ms", "atty", "prof", "miss", "mrs" };
    private String[] suffixes = { "jr", "sr", "ii", "iii", "iv", "v", "vi", "esq", "2nd", "3rd", "jd", "phd",
            "md", "cpa" };

    public NameParser() {
    }

    public NameParser(String name) {
        parse(name);
    }

    private void reset() {
        firstName = lastName = middleName = "";
        middleNames = new ArrayList<String>();
        titlesBefore = new ArrayList<String>();
        titlesAfter = new ArrayList<String>();
    }

    private boolean isOneOf(String checkStr, String[] titles) {
        for (String title : titles) {
            if (checkStr.toLowerCase().startsWith(title))
                return true;
        }
        return false;
    }

    public void parse(String name) {
        if (StringUtils.isBlank(name))
            return;
        this.reset();
        String[] words = name.split(" ");
        boolean isFirstName = false;

        for (String word : words) {
            if (StringUtils.isBlank(word))
                continue;
            if (word.charAt(word.length() - 1) == '.') {
                if (!isFirstName && !this.isOneOf(word, prefixes)) {
                    firstName = word;
                    isFirstName = true;
                } else if (isFirstName) {
                    middleNames.add(word);
                } else {
                    titlesBefore.add(word);
                }
            } else {
                if (word.endsWith(","))
                    word = StringUtils.chop(word);
                if (isFirstName == false) {
                    firstName = word;
                    isFirstName = true;
                } else {
                    middleNames.add(word);
                }
            }
        }
        if (middleNames.size() > 0) {
            boolean stop = false;
            List<String> toRemove = new ArrayList<String>();
            for (int i = middleNames.size() - 1; i >= 0 && !stop; i--) {
                String str = middleNames.get(i);
                if (this.isOneOf(str, suffixes)) {
                    titlesAfter.add(str);
                } else {
                    lastName = str;
                    stop = true;
                }
                toRemove.add(str);
            }
            if (StringUtils.isBlank(lastName) && titlesAfter.size() > 0) {
                lastName = titlesAfter.get(titlesAfter.size() - 1);
                titlesAfter.remove(titlesAfter.size() - 1);
            }
            for (String s : toRemove) {
                middleNames.remove(s);
            }
        }
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getMiddleName() {
        if (StringUtils.isBlank(this.middleName)) {
            for (String name : middleNames) {
                middleName += (name + " ");
            }
            middleName = StringUtils.chop(middleName);
        }
        return middleName;
    }

    public List<String> getTitlesBefore() {
        return titlesBefore;
    }

    public List<String> getTitlesAfter() {
        return titlesAfter;
    }

}

Тестовый пример:

import junit.framework.Assert;

import org.junit.Test;

public class NameParserTest {

    private class TestData {
        String name;

        String firstName;
        String lastName;
        String middleName;

        public TestData(String name, String firstName, String middleName, String lastName) {
            super();
            this.name = name;
            this.firstName = firstName;
            this.lastName = lastName;
            this.middleName = middleName;
        }

    }

    @Test
    public void test() {

        TestData td[] = { new TestData("Henry \"Hank\" J. Fasthoff IV", "Henry", "\"Hank\" J.", "Fasthoff"),
                new TestData("April A. (Caminez) Bentley", "April", "A. (Caminez)", "Bentley"),
                new TestData("fff lll", "fff", "", "lll"),
                new TestData("fff mmmmm lll", "fff", "mmmmm", "lll"),
                new TestData("fff mmm1      mm2 lll", "fff", "mmm1 mm2", "lll"),
                new TestData("Mr. Dr. Tom Jones", "Tom", "", "Jones"),
                new TestData("Robert P. Bethea Jr.", "Robert", "P.", "Bethea"),
                new TestData("Charles P. Adams, Jr.", "Charles", "P.", "Adams"),
                new TestData("B. Herbert Boatner, Jr.", "B.", "Herbert", "Boatner"),
                new TestData("Bernard H. Booth IV", "Bernard", "H.", "Booth"),
                new TestData("F. Laurens \"Larry\" Brock", "F.", "Laurens \"Larry\"", "Brock"),
                new TestData("Chris A. D'Amour", "Chris", "A.", "D'Amour") };

        NameParser bp = new NameParser();
        for (int i = 0; i < td.length; i++) {
            bp.parse(td[i].name);
            Assert.assertEquals(td[i].firstName, bp.getFirstName());
            Assert.assertEquals(td[i].lastName, bp.getLastName());
            Assert.assertEquals(td[i].middleName, bp.getMiddleName());
        }
    }

}

Ответ 2

Возможно, вы могли бы попробовать GATE компонент для извлечения искомого объекта? Он создает в jape списки грамматики и справочника географических названий, чтобы извлекать имена, фамилии и т.д. Между прочим. См. эту страницу.

Ответ 4

Лично я бы выбрал регулярные выражения. Здесь хороший intro. Они быстры, сжаты и всегда делают то, что вы хотите.

Если вы хотите оставаться в пределах java sdk, используйте String tokenizers.

Немного более низкий уровень JavaCC, основанный на Java генератор парсера. Здесь ссылка на учебник.

Альтернативой javaCC является ANTLR, с которым у меня лично были хорошие впечатления.

Ответ 5

Этот простой код может помочь:

import java.util.ArrayList;
import java.util.List;

public class NamesConverter {

    private List<String> titlesBefore = new ArrayList<>();
    private List<String> titlesAfter = new ArrayList<>();
    private String firstName = "";
    private String lastName = "";
    private List<String> middleNames = new ArrayList<>();

    public NamesConverter(String name) {
        String[] words = name.split(" ");
        boolean isTitleAfter = false;
        boolean isFirstName = false;

        int length = words.length;
        for (String word : words) {
            if (word.charAt(word.length() - 1) == '.') {
                if (isTitleAfter) {
                    titlesAfter.add(word);
                } else {
                    titlesBefore.add(word);
                }
            } else {
                isTitleAfter = true;
                if (isFirstName == false) {
                    firstName = word;
                    isFirstName = true;
                } else {
                    middleNames.add(word);
                }
            }
        }
        if (middleNames.size() > 0) {
            lastName = middleNames.get(middleNames.size() - 1);
            middleNames.remove(lastName);
        }
    }

    public List<String> getTitlesBefore() {
        return titlesBefore;
    }

    public List<String> getTitlesAfter() {
        return titlesAfter;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public List<String> getMiddleNames() {
        return middleNames;
    }

    @Override
    public String toString() {
        String text = "Titles before :" + titlesBefore.toString() + "\n"
                + "First name :" + firstName + "\n"
                + "Middle names :" + middleNames.toString() + "\n"
                + "Last name :" + lastName + "\n"
                + "Titles after :" + titlesAfter.toString() + "\n";

        return text;
    }
}

Например, этот ввод:

    NamesConverter ns = new NamesConverter("Mr. Dr. Tom Jones");
    NamesConverter ns1 = new NamesConverter("Ing. Tom Ridley Bridley Furthly Murthly Jones CsC.");
    System.out.println(ns);
    System.out.println(ns1);

Имеет этот вывод:

Titles before :[Mr., Dr.]
First name :Tom
Middle names :[]
Last name :Jones
Titles after :[]

Titles before :[Ing.]
First name :Tom
Middle names :[Ridley, Bridley, Furthly, Murthly]
Last name :Jones
Titles after :[CsC.]