分析单词文本的算法

时间:2009-05-09 09:37:29

标签: java php algorithm string nlp

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

"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"
..

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

5 个答案:

答案 0 :(得分: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开始到单词编号j的所有短语,大于i(因此所有短语都至少有两个单词)。

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

如果您有任何编程经验,这似乎很清楚,但以防万一:for语句是循环[如for(i=1; i<=n; i++)],split是一些函数,它需要一个字符串并将其拆分为一个单词数组 - 这不是完全无关紧要的,但可能有一个库函数来执行此操作,len给出数组的长度,join将它们与空格重新组合在一起介于两者之间,语法[i:j]表示从ij包含的所有元素(在python中,这实际上是[i:j+1])。哦,我隐含地假设数组从索引1开始而不是零;我将更改为基于0的C数组作为练习...

最后,回答具体问题:

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

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

答案 1 :(得分: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 :-)。这只是为了说明如何从你要求的句子中输出单词分组。

执行我在原始答案中提到的所有花哨的句子检测和标点符号删除。

答案 2 :(得分:2)

只需将句子标记化并使用CombinationGenerator。该算法由Kenneth H.Rosen,Discrete Mathematics and Its Applications,2nd edition(NY:McGraw-Hill,1991),第284-286页描述。

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

答案 3 :(得分:1)

可以使用str_word_count();并根据需要构建它。

答案 4 :(得分:1)

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