2009-08-25 41 views
16

Tôi đang tìm thư viện có chức năng tương tự với mô-đun Perl Lingua::EN::NameParse. Về cơ bản, tôi muốn phân tích các chuỗi như 'Mr. Bob R. Smith 'vào các thành phần tiền tố, tên, họ và tên hậu tố. Google đã không được giúp đỡ nhiều trong việc tìm kiếm một cái gì đó như thế này và tôi không muốn cuộn của riêng tôi nếu có thể. Bất cứ ai biết về một thư viện Java OSS có thể làm điều này một cách tinh vi?Thư viện phân tích cú pháp tên Java?

Trả lời

0

Cá nhân, tôi sẽ chọn tham gia regular expressions. Đây là một số intro tốt. Chúng nhanh chóng, súc tích và luôn luôn làm những gì bạn muốn.

Nếu bạn muốn ở trong ranh giới của sdk java, hãy sử dụng String tokenizers.

Thấp hơn một chút là JavaCC, trình tạo trình phân tích cú pháp dựa trên java. Đây là link to a tutorial.

Một giải pháp thay thế cho javaCC là ANTLR, cá nhân tôi đã có trải nghiệm tốt.

5

Có thể bạn có thể thử GATE thành phần trích xuất thực thể được đặt tên? Nó đã xây dựng trong jape ngữ pháp và danh sách gazetteer để trích xuất tên đầu tiên, tên cuối cùng vv trong số những thứ khác. Xem trang this.

+1

+1 bạn có thể chỉ cho tôi một ví dụ về cách phân tích tên sử dụng GATE –

0

mã đơn giản này có thể giúp:

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

Ví dụ đầu vào này:

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

Có kết quả này:

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

Tôi chỉ không thể tin được một người nào đó chưa chia sẻ thư viện cho điều này - tôi cũng đã xem github và có một phân tích cú pháp tên javascript có thể được dễ dàng dịch sang java: https://github.com/joshfraser/JavaScript-Name-Parser

Tôi cũng sửa đổi mã trong một trong các câu trả lời để làm việc tốt hơn một chút và tôi đã bao gồm một trường hợp thử nghiệm:

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

} 

thử nghiệm trường hợp:

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

Phương pháp này isOneOf nên được viết lại như sau: isOneOf boolean tin (String checkStr, String [] tiêu đề) { cho (Tiêu đề chuỗi: tiêu đề) nếu (checkStr.equalsIgnoreCase (tiêu đề)) trả về true; trả về false; } Bởi vì hiện tại, nó sẽ nhận ra tất cả các tên bắt đầu bằng V làm hậu tố. – KimvdLinde

3

Apache Commons có lớp 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

Bạn có thể tìm thấy nó trên [github] (https://github.com/apache/commons-text/blob/master/src/main/java/org/apache/commons/text/names/HumanNameParser.java).Phiên bản hiện tại vẫn là SNAPSHOT. –

Các vấn đề liên quan