我正在使用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处理标题和数字?
答案 0 :(得分:4)
这是一个棘手的情况,我已经提出了一个棘手的解决方案,但它仍然有效。我自己也是Java的新手,所以如果经验丰富的老手想要编辑或评论它并使其更专业,请让我看起来更好。
我基本上为你已经检查的内容添加了一些控制措施,看看是否存在教授Mrs. Mrs. Mrs.等等。如果这些单词存在,它只是跳过那个休息并移动到下一个休息时间(保持原始起始位置)寻找NEXT结束(最好是一个不会在另一个博士或先生等之后结束)
我包括我的完整程序,所以你可以看到它:
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开始不会移动,除非字符串看起来准备好成为一个句子。这需要第一句话:
"Prof."
并检查是否由于一个奇怪的单词而破坏(即它是否有教授或w / e在句子中可能导致该中断)如果确实如此,那么tempStart不会移动它停留在那里,等待下一个块回来。在我稍微复杂一点的句子中,下一个块也有一个奇怪的词弄乱了休息时间:
"Roberts and Dr."
它需要那个大块,因为它有一个博士,它继续到第三个句子:
"Andrews trying to solve a problem by writing a 1.200 lines of code."
一旦它到达第三个被破坏的块并且没有任何可能导致错误中断的奇怪标题,它然后从临时启动(仍然在开始时)开始到当前结束,基本上将所有三个部分连接在一起
现在它将临时开始设置为当前&#39;结束&#39;并继续。
就像我说的那样,这可能不是一种迷人的方式来获得你想要的东西,但是没有其他人自愿参加,而且它起作用耸肩
答案 1 :(得分:0)
如果Prof. Robert
以大写字母开头,Roberts
似乎只会被拆分。
如果Roberts
以小写r
开头,则不会被拆分。
所以......我猜这就是BreakIterator
处理句号的方式。
我确信进一步阅读the documentation将解释如何修改此行为。