【问题标题】:Algorithm for analyzing text of words分析单词文本的算法
【发布时间】:2009-05-09 09:37:29
【问题描述】:

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

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

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

【问题讨论】:

  • 但是这些短语的构建规则是什么?
  • 看样子是连续的2-3个字……
  • 自然语言处理 == 痛苦的世界
  • 我完全不清楚这个问题是否涉及任何自然语言处理!问题中定义的“短语”似乎没有任何语义。
  • “你懂的。”啊,伟大规格的经典标志。

标签: java php algorithm string nlp


【解决方案1】:

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

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

然后,当你剩下一个单词数组时,它就变得更简单了:

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 :-)。它只是为了说明如何根据您的要求从句子中输出单词分组。

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

【讨论】:

  • 你能给出一个 php/c/java 之类的 for 循环示例吗?我很难理解它的作用,因为我不熟悉语法。如果你能在 java 中显示代码,那就太棒了
【解决方案2】:

好吧,我不知道 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&lt;=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) 并返回字符串,尽管某些语言有办法使这更容易。

【讨论】:

  • 如果您阅读他的第一句话,您会发现他不会 PHP 或 Java。另外,给出的伪代码应该足够简单,只要有一些基本的 Java 知识和一些搜索,就可以自己翻译成 Java。
  • 如果我能理解伪代码,那对我来说意义不大。他有 java 作为他的标签之一..
  • 是的,但这只是意味着我用java作为标签回答了一些其他问题......无论如何,你不明白什么?请参阅上面的一些提示或提出具体问题,也许我可以提供帮助!
【解决方案3】:

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

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

【讨论】:

  • 再次(如 Jess 的尝试)我们不想要所有可能的组合 - 只是连续的条目。这是一个更容易的问题(解决了几次以上)!
【解决方案4】:

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

【讨论】:

  • 请注意,ShingleMatrixFilter 已被弃用,将在 4.0 中删除。您可能需要考虑使用 ShingleFilter。
【解决方案5】:

可以与str_word_count(); 一起玩,并随心所欲地构建它。

【讨论】:

    猜你喜欢
    • 2012-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 2014-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多