这是我最近的问题(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)将伪造的单词添加到黑名单中,如“许可证”,“该”等。这些通常在许可证信息的文件开头找到。
4)将每种语言最重要的五个单词添加到白名单中。这些是在给定语言的大多数源代码中找到的单词,但不足以进入直方图。例如,对于C / C ++,我在白名单中有:#include,#define,#ifdef,#ifnf和#endif。
5)强调文件的开头,因此在前50-100行中找到更多的单词
6)在进行单词直方图时,使用@words = split(/[\s\(\){}\[\];.,=]+/, $_);
对文件进行标记化。对于我认为的大多数语言来说,这应该没问题(给我最好的结果)。对于每种语言,最终结果中大约有10-20个最常用的单词
7)完成直方图后,删除黑名单中找到的所有单词,并添加白名单中的所有单词。
8)编写一个程序,以与脚本相同的方式处理文本文件 - 使用相同的规则进行标记。如果在直方图数据中找到单词,请将点添加到正确的语言。直方图中仅对应一种语言的单词应该添加更多的点,属于多种语言的单词应该添加更少的点。
欢迎提出意见。目前在大约1000个文本文件中我得到80个未知数(主要是在非常短的文件上 - 主要是只有一两行的javascript)。大约20个文件被识别错误。文件大小约为11kB,范围从100字节到100字节(总共大约11MB)。它需要一秒钟来处理它们,这对我来说已经足够了。
答案 0 :(得分:3)
我认为你是从错误的角度来看待这个问题。根据您的描述,听起来您正在构建分类器。一个好的分类器需要区分不同的类;它不需要精确估计输入和最可能的类之间的对应关系。
实际上:您的分类器不需要精确评估某个输入与C ++的接近程度;它只需要确定输入是否更像C而不是C ++。这使您的工作变得更加轻松 - 大多数当前“未知”案例将接近一种或两种语言,即使它们不超过您的基本阈值。
现在,一旦你意识到这一点,你也会看到你的分类器需要什么样的训练:不是样本文件的一些随机方面,而是两种语言的区别。因此,当您解析C样本和C ++样本时,您将看到#include
未将它们分开。但是,class
和template
在C ++中会更为常见。另一方面,#include
区分C ++和Java。
除了关键字之外,您还可以使用其他方面。例如,最明显的是{
的频率,;
同样具有区别性。分类器的另一个非常有用的功能是针对不同语言的注释令牌。当然,基本问题是自动识别它们。同样,将//
,/*
,'
,--
,#
和!
硬编码为伪关键字会有所帮助。
这也标识了另一个分类规则:SQL通常在一行的开头有--
,而在C中它通常会出现在其他地方。因此,分类器也可以考虑上下文。
答案 1 :(得分:2)
使用Google代码搜索来学习关键字集的权重:C ++中的#include获得672.000次点击,Python只有5000次。
您可以通过查看总计语言的结果数来规范化结果: C ++提供大约770.000个文件,而Python返回120.000。
因此“#include”在Python文件中极为罕见,但几乎存在于每个C ++文件中。 (现在你仍然需要学会区分C ++和C.)剩下的就是对概率进行正确的推理。
答案 2 :(得分:1)
您需要对查询数据进行一些排他性
在教授您期望的编程语言时,您应该搜索一种或几种语言的典型单词。如果一个单词出现在同一语言的几个代码文件中,但很少或没有出现在其他语言文件中,则强烈建议使用该语言。
因此,通过选择一种语言或一组语言专用的单词,可以在查找侧计算单词的分数。找到这些单词中的几个,并通过添加分数得到这些单词的交集,并找到您将拥有的语言。
答案 3 :(得分:0)
在回答您的其他问题时,有人推荐naïve Bayes classifier。您应该实施此建议,因为该技术擅长根据区别特征进行分离。您提到了while
关键字,但由于许多语言都使用它,因此不太可能有用 - 而且贝叶斯分类器不会将其视为有用。
问题的一个有趣部分是如何标记未知程序。空白分隔的块是一个不错的粗略开始,但有意义的超出这个将是棘手的。