【发布时间】:2011-04-09 04:37:24
【问题描述】:
这是对我最近的问题 (Code for identifying programming language in a text file) 的跟进。我真的很感谢我得到的所有答案,它对我很有帮助。 我完成这项任务的代码是完整的,并且运行良好 - 快速且相当准确。
我使用的方法如下:我有一个“学习”perl 脚本,它通过对一组示例文件进行单词直方图来识别语言中最常用的单词。这些数据然后由 c++ 程序加载,然后检查给定的文本并根据找到的单词为每种语言累积分数,然后简单地检查哪种语言的分数最高。
现在我想让它变得更好,并在识别质量上做一些工作。 问题是我经常得到“未知”的结果(许多语言的得分都很少,但没有一个比我的阈值大)。经过一些调试、研究等,我发现这可能是因为所有单词都被认为是平等的。这意味着例如看到“#include”与看到“while”具有相同的效果-两者都表明它可能是c / c ++(我现在忽略了“while”在许多其他中使用的事实语言),但当然在较大的 .cpp 文件中可能有大量的“while”,但大多数时候只有几个“#include”。
所以“#include”更重要这一事实被忽略了,因为我想不出一个好的方法来识别一个词是否比另一个词更重要。现在继续请注意,创建数据的脚本是相当愚蠢的,它只有一个单词直方图,并且对于每个选择的单词,它都分配 1 分。它甚至不看单词(所以如果有一个“#&|?/”在一个文件中,它可能经常被选为一个好词)。
我还希望数据创建部分完全自动化,所以没有人应该查看数据并更改它们、更改分数、更改单词等。所有的“brainz”都应该在脚本和 cpp 程序中.
有人对如何识别关键字或更一般地识别重要词有建议吗? 一些可能有帮助的事情:我知道每个词的出现次数和总词数(所以可以计算一个比率)。我还考虑过删除诸如 ; 之类的字符,因为直方图脚本通常会放置例如“继续”;结果,但重要的词是“继续”。最后一点:所有相等性检查都是针对完全匹配完成的——没有子字符串,区分大小写。这主要是因为速度,但子字符串可能会有所帮助(或伤害,我不知道)......
注意:感谢所有愿意回答的人,你帮了我很多。
我的工作几乎完成了,所以我将描述我为获得好的结果所做的工作。
1) 获得一个体面的训练集,每种语言大约 30-50 个来自各种来源的文件,以避免编码风格偏差
2) 编写一个执行单词直方图的 perl 脚本。实施黑名单和白名单(更多信息见下文)
3) 将虚假词添加到黑名单中,如“license”、“the”等。这些词经常出现在许可证信息中的文件开头。
4) 将每种语言大约五个最重要的单词添加到白名单中。这些是在给定语言的大多数源代码中都可以找到的单词,但频率不足以进入直方图。例如,对于 C/C++,我在白名单中有:#include、#define、#ifdef、#ifndef 和 #endif。
5) 强调文件的开头,因此给前 50-100 行中的单词加分
6)在做单词直方图时,使用@words = split(/[\s\(\){}\[\];.,=]+/, $_);标记文件对于我认为的大多数语言来说应该没问题(给我最好的结果)。对于每种语言,在最终结果中包含大约 10-20 个最常用的单词。
7) 直方图完成后,删除所有在黑名单中找到的单词,并添加所有在白名单中找到的单词
8) 编写一个程序,以与脚本相同的方式处理文本文件 - 使用相同的规则进行标记。如果在直方图数据中找到一个单词,则将点添加到正确的语言。直方图中只对应一种语言的词要多加分,属于多种语言的要少加分。
欢迎评论。目前在大约 1000 个文本文件中,我得到了 80 个未知数(主要是在极短的文件上——主要是只有一两行的 javascript)。大约 20 个文件被识别错误。文件大小约为 11kB,范围从 100 字节到 100 kBytes(总共几乎 11MB)。处理它们需要一秒钟,这对我来说已经足够了。
【问题讨论】:
-
我很肯定我至少使用过一种语言,其中“the”是具有真正含义的关键字。我现在不记得了。超话,也许吧?一些更晦涩的小众语言?
-
@David Thornley:我知道,没有什么是完美的。问题是,像“the”这样非常常见的词最好忽略,因为它们会偏向检测 - 英文评论太常见(以及许可证信息)。独特的语言关键字比在各种语言中使用的单词要好得多(如果、for、while 真的没用的话)。
标签: c++ perl text-processing language-recognition