2009-08-25 11 views
16

Poszukuję biblioteki podobnej funkcjonalnie do modułu Perl Lingua::EN::NameParse. Zasadniczo chciałbym przeanalizować ciągi takie jak "Mr. Bob R. Smith "na komponenty przyrostka, imienia, nazwiska i sufiksu nazwy. Google nie pomogło w znalezieniu czegoś takiego i wolałbym nie używać własnych, jeśli to możliwe. Ktoś wie o bibliotece Java OSS, która potrafi to zrobić w wyrafinowany sposób?Biblioteka analizy nazw Java?

Odpowiedz

5

Może mógłbyś wypróbować komponent do ekstrakcji nazwanej encji GATE? Został zbudowany w jape gramatykę i listy gazeterów, aby wyodrębnić imiona, nazwiska itp., Między innymi. Zobacz stronę this.

+1

+1 możesz pokazać mi przykład, jak analizować przy użyciu nazwy GATE –

0

Ten prosty kod może pomóc:

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; 
    } 
} 

Na przykład wejście:

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); 

Ma to wyjście:

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.] 
8

Po prostu nie mogę uwierzyć komuś nie udostępnił do tego biblioteki - dobrze zaglądałem github i tam javascript nazwa parser, który może być łatwo przetłumaczony na Java: https://github.com/joshfraser/JavaScript-Name-Parser

ja również zmodyfikowany kod w jednym z odpowiedziami do pracy trochę lepiej i obejmowały przypadek testowy:

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; 
    } 

} 

testową Sprawa:

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()); 
     } 
    } 

} 
+0

Metoda isOneOf powinny być zapisane jako: prywatnej logiczną isOneOf (String checkStr, String [] tytułów) { for (tytuł ciągu: tytuły) if (checkStr.equ.IgnoreCase (title)) return true; return false; } Ponieważ obecnie rozpozna wszystkie nazwy zaczynające się od litery V jako sufiksu. – KimvdLinde

3

Apache Commons ma klasę HumanNameParser.

https://commons.apache.org/sandbox/commons-text/jacoco/org.apache.commons.text.names/HumanNameParser.java.html

Name nextName = parser.parse("James C. ('Jimmy') O'Dell, Jr.") 
String firstName = nextName.getFirstName(); 
String nickname = nextName.getNickName(); 
+0

Można go znaleźć na [github] (https://github.com/apache/commons-text/blob/master/src/main/java/org/apache/commons/text/names/HumanNameParser.java).Obecna wersja nadal jest jednak SNAPSHOT. –