1

我想要一种算法,可以在文本块中创建所有可能的短语。例如,在文本中:

"My username is click upvote. I have 4k rep on stackoverflow"

它将创建以下组合:

"My username"
"My Username is"
"username is click"
"is click"
"is click upvote"
"click upvote"
"i have"
"i have 4k"
"have 4k"
..

你明白了。基本上,重点是从句子中获得所有可能的“短语”组合。关于如何最好地实现这一点的任何想法?

4

5 回答 5

5

基本上,您需要首先将文本块分成句子。这很棘手,即使在英语中也是如此,因为您需要注意句号、问号、感叹号和任何其他句子终止符。

然后在删除所有标点符号(逗号、分号、冒号等)后一次处理一个句子。

然后,当您留下一组单词时,它变得更简单:

for i = 1 to num_words-1:
    for j = i+1 to num_words:
        phrase = words[i through j inclusive]
        store phrase

就是这样,非常简单(在对文本块进行初始按摩之后,这可能不像您想象的那么简单)。

这将为您提供每个句子中包含两个或多个单词的所有短语。

分句、分词、去除标点符号等将是最难的部分,但我已经向您展示了一些简单的初始规则。每次文本块破坏算法时,都应添加其余部分。

更新:

根据要求,这里有一些给出短语的 Java 代码:

public class testme {
    public final static String text =
        "My username is click upvote." +
        " I have 4k rep on stackoverflow.";

 

    public static void procSentence (String sent) {
        System.out.println ("==========");
        System.out.println ("sentence [" + sent + "]");

        // Split sentence at whitspace into array.

        String [] sa = sent.split("\\s+");

        // Process each starting word.

        for (int i = 0; i < sa.length - 1; i++) {

            // Process each phrase.

            for (int j = i+1; j < sa.length; j++) {

                // Build the phrase.

                String phrase = sa[i];
                for (int k = i+1; k <= j; k++) {
                    phrase = phrase + " " + sa[k];
                }

                // This is where you have your phrase. I just
                // print it out but you can do whatever you
                // wish with it.
                System.out.println ("   " + phrase);
            }
        }
    }

 

    public static void main(String[] args) {
        // This is the block of text to process.

        String block = text;
        System.out.println ("block    [" + block + "]");

        // Keep going until no more sentences.

        while (!block.equals("")) {
            // Remove leading spaces.

            if (block.startsWith(" ")) {
                block = block.substring(1);
                continue;
            }

            // Find end of sentence.

            int pos = block.indexOf('.');

            // Extract sentence and remove it from text block.

            String sentence = block.substring(0,pos);
            block = block.substring(pos+1);

            // Process the sentence (this is the "meat").

            procSentence (sentence);

            System.out.println ("block    [" + block + "]");
        }
        System.out.println ("==========");
    }
}

输出:

block    [My username is click upvote. I have 4k rep on stackoverflow.]
==========
sentence [My username is click upvote]
   My username
   My username is
   My username is click
   My username is click upvote
   username is
   username is click
   username is click upvote
   is click
   is click upvote
   click upvote
block    [ I have 4k rep on stackoverflow.]
==========
sentence [I have 4k rep on stackoverflow]
   I have
   I have 4k
   I have 4k rep
   I have 4k rep on
   I have 4k rep on stackoverflow
   have 4k
   have 4k rep
   have 4k rep on
   have 4k rep on stackoverflow
   4k rep
   4k rep on
   4k rep on stackoverflow
   rep on
   rep on stackoverflow
   on stackoverflow
block    []
==========

现在,请记住这是非常基本的 Java(有些人可能会说它是用 Java 方言编写的 C :-)。它只是为了说明如何根据您的要求从句子中输出单词分组。

它并没有完成我在原始答案中提到的所有花哨的句子检测和标点删除。

于 2009-05-09T10:55:50.553 回答
5

好吧,我不知道 PHP 或 java,但基本上你想要对文本中的所有单词进行双重循环。这是一些伪代码:

words = split(text)
n = len(words)
for i in 1...n-1 {        // i = first word in phrase 
    for j in i+1...n {       // j = last word in phrase
        phrase = join(words[i:j])
        print phrase
    }
}

请注意,第二个循环从 i 开始,而不是 1。这将为您提供从单词编号 i 开始到大于 i 的单词编号 j 的所有短语(因此所有短语至少有两个单词)。

啊,我刚刚意识到您可能不希望短语跨越句子边界。所以你需要一个外部循环,它首先将文本分成句子,然后在每个句子上运行它。

如果您有任何编程经验,这似乎很清楚,但以防万一:for语句是循环 [like for(i=1; i<=n; i++)],split是一些函数,它接受一个字符串并将其拆分为一个单词数组——这并非完全无关紧要,但可能有一个库函数可以做到这一点,len给出数组的长度,join将它们放回一起,中间有空格,语法[i:j]意味着所有元素 fromijinclusive (在python中,这实际上是[i:j+1])。哦,我已经隐含地假设数组从索引 1 而不是零开始;我将更改为基于 0 的C数组作为练习...

最后,回答具体问题:

  • 请注意,“第二个”循环实际上是一个内部循环;对于i(短语的第一个单词)的每个值,我们循环i+1到句子的末尾以给出短语的最后一个单词。

  • 现在我们有了第一个单词和最后一个单词的数量,这个join函数——你必须编写它——将各个字符串word[i], word[i+1], ... word[j]与它们之间的空格连接起来以形成短语。在实践中,这可能意味着函数可以声明为类似join(words, i, j)并返回字符串,尽管有些语言有办法使这更容易。

于 2009-05-09T09:42:10.683 回答
2

只需对句子进行标记并使用 CombinationGenerator。该算法由 Kenneth H. Rosen 描述,离散数学及其应用,第 2 版(纽约:McGraw-Hill,1991),第 284-286 页。

这是代码和使用示例: http ://www.merriampark.com/comb.htm

于 2009-05-09T15:10:56.000 回答
1

可以随心所欲地玩str_word_count();和构建它。

于 2009-05-09T17:51:24.950 回答
1

您可能已经知道此类短语的技术术语是 Shingle。您可以使用 Lucene 的ShingeMatrixFilter为输入文本获取带状疱疹。

于 2010-05-23T03:44:08.450 回答