5

我在 Java 中使用 BreakIterator 类将段落分成句子。这是我的代码:

public Map<String, Double> breakSentence(String document) {
    sentences = new HashMap<String, Double>();
    BreakIterator bi = BreakIterator.getSentenceInstance(Locale.US);
    bi.setText(document);

    Double tfIdf = 0.0;
    int start = bi.first();
    for(int end = bi.next(); end != BreakIterator.DONE; start = end, end = bi.next()) {
        String sentence = document.substring(start, end);

        sentences.put(sentence, tfIdf);
    }

    return sentences;
}

问题是当段落包含标题或数字时,例如:

“罗伯茨教授试图通过编写 1.200 行代码来解决问题。”

我的代码将产生的是:

sentences :
Prof
Roberts trying to solve a problem by writing a 1
200 lines of code

由于标题和数字中的句点,而不是 1 个句子。

有没有办法解决这个问题以使用 Java 处理标题和数字?

4

2 回答 2

6

好吧,这有点棘手,我想出了一个棘手的解决方案,但它仍然有效。我自己是 Java 新手,所以如果一位经验丰富的老手想要编辑或评论它并通过各种方式使其更专业,请让我看起来更好。

我基本上在你已经必须检查的内容上添加了一些控制措施,看看是否存在诸如 Dr. Prof. Mr. Mrs. 之类的词,如果这些词存在,它就会跳过那个休息时间并移动到下一个休息时间(保持原始开始位置)寻找下一个结束(最好不是在另一个博士或先生等之后结束)

我包括我的完整程序,所以你可以看到它:

import java.text.BreakIterator;
import java.util.*;

public class TestCode {

    private static final String[] ABBREVIATIONS = {
        "Dr." , "Prof." , "Mr." , "Mrs." , "Ms." , "Jr." , "Ph.D."
    };

    public static void main(String[] args) throws Exception {

        String text = "Prof. Roberts and Dr. Andrews trying to solve a " +
                      "problem by writing a 1.200 lines of code. This will " +
                      "work if Mr. Java writes solid code.";

        for (String s : breakSentence(text)) {
              System.out.println(s);
        }
    }

    public static List<String> breakSentence(String document) {

        List<String> sentenceList = new ArrayList<String>();
        BreakIterator bi = BreakIterator.getSentenceInstance(Locale.US);
        bi.setText(document);
        int start = bi.first();
        int end = bi.next();
        int tempStart = start;
        while (end != BreakIterator.DONE) {
            String sentence = document.substring(start, end);
            if (! hasAbbreviation(sentence)) {
                sentence = document.substring(tempStart, end);
                tempStart = end;
                sentenceList.add(sentence);
            }
            start = end; 
            end = bi.next();
        }
        return sentenceList;
    }

    private static boolean hasAbbreviation(String sentence) {
        if (sentence == null || sentence.isEmpty()) {
            return false;
        }
        for (String w : ABBREVIATIONS) {
            if (sentence.contains(w)) {
                return true;
            }
        }
        return false;
    }
}

这样做,基本上是设置了两个起点。最初的起点(您使用的起点)仍然在做同样的事情,但 temp start 不会移动,除非字符串看起来准备好变成一个句子。取第一句:

"Prof."

并检查是否因为一个奇怪的词而中断(即它是否有可能导致中断的句子中的教授或 w/e)如果确实如此,那么 tempStart 不会移动,它会停留在那里并且等待下一个块回来。在我稍微复杂一点的句子中,下一个块也有一个奇怪的词弄乱了休息:

"Roberts and Dr."

它占用了那个块,因为它有一个 Dr. ,所以它继续到句子的第三块:

"Andrews trying to solve a problem by writing a 1.200 lines of code."

一旦它到达被破坏的第三块并且没有任何可能导致错误中断的奇怪标题,它就会从临时开始(仍处于开头)到当前结束,基本上将所有三个部分连接在一起。

现在它将临时开始设置为当前的“结束”并继续。

就像我说的那样,这可能不是获得你想要的东西的迷人方式,但没有其他人自愿提供,它耸了耸肩

于 2013-06-18T05:05:29.063 回答
0

似乎只有以大写字母开头Prof. Robert的 s 才会被拆分。Roberts

如果Roberts以小写字母开头r,则不会拆分

所以......我想这就是BreakIterator处理时期的方式。

我确信进一步阅读文档将解释如何修改此行为。

于 2013-06-18T02:41:36.443 回答