【问题标题】:Split paragraph into sentences with titles and numbers将段落拆分为带有标题和数字的句子
【发布时间】:2013-06-14 02:45:24
【问题描述】:

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

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

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

我的代码将产生的是:

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

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

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

【问题讨论】:

  • 我很困惑...文档中的这一行表明应该是一种方法:“句子边界分析允许选择正确解释数字和缩写中的句点,以及引号和括号等尾随标点符号......“也就是说,我从未使用过BreakIterator
  • 1.200 对我来说没有被拆分,尽管 Prof. 确实被拆分了。
  • 您可能希望为此创建自己的方法。并为教授设置例外。 “先生。” “太太。”或您在输入中可能遇到的任何其他变体。
  • @user93353 - 如果下一个单词以大写字母开头,Prof 将不会被拆分...
  • @leigero 你能给我一个关于设置处理它的方法的说明吗?正则表达式会解决这个问题吗?

标签: java text-segmentation


【解决方案1】:

这有点棘手,我想出了一个棘手的解决方案,但它仍然有效。我自己是 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."

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

"Roberts and Dr."

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

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

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

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

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

【讨论】:

  • 感谢您的代码,您能否详细说明您的代码如何处理像 1.200 这样的句号?
  • 编号 pert 由 BreakIterator 自动处理。 Oracle 文档说:“句子边界分析允许选择正确解释数字和缩写中的句点,以及尾随标点符号,如引号和括号。”所以我不知道你为什么一开始就没有正确地做到这一点。
  • 您提供了,所以我编辑了您的代码以使其更具 Java 风格...如果您愿意,请随时拒绝我的编辑。
  • 太棒了!我看到它的编辑非常多。我喜欢看其他人如何修复代码,因为我没有从“行业”中学到东西,所以很高兴看到现实世界是如何组织事物的。
  • 酷。目前我认为它并不适用于所有场景。我认为,如果缩写后面跟着一个不以大写字母开头的单词,那是行不通的……所以,这不好。我相信原始版本有同样的问题(在我编辑之前)。
【解决方案2】:

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

如果Roberts 以小写r 开头,则它不会被拆分。

所以...我想这就是BreakIterator 处理句号的方式。

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

【讨论】:

    猜你喜欢
    • 2013-05-21
    • 2011-01-10
    • 1970-01-01
    • 2020-09-21
    • 2013-08-13
    • 1970-01-01
    • 2014-06-01
    • 2016-10-09
    相关资源
    最近更新 更多