【问题标题】:Identifying keywords of a (programming) language识别(编程)语言的关键字
【发布时间】: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


【解决方案1】:

您需要在查找数据中获得一些排他性。
在教授您期望的编程语言时,您应该搜索一种或几种语言的典型单词。如果一个词出现在同一种语言的多个代码文件中,但在其他语言文件中很少出现或没有出现,则强烈建议使用该语言。
因此,可以在查找端通过选择一种语言或一组语言独有的单词来计算单词的分数。找到其中的几个单词并通过添加分数得到它们的交集,然后找到您将拥有的语言。

【讨论】:

    【解决方案2】:

    使用 Google 代码搜索来学习一组关键字的权重:#include 在 C++ 中获得 672.000 次点击,在 Python 中只有 ~5000。

    您可以通过查看该语言的总结果数来规范化结果: C++ 提供大约 770.000 个文件,而 Python 返回 120.000。

    因此,“#include”在 Python 文件中极为罕见,但几乎存在于每个 C++ 文件中。 (当然,现在您仍然必须学习区分 C++ 和 C。)剩下的就是对概率进行正确的推理。

    【讨论】:

      【解决方案3】:

      在回答您的其他问题时,有人推荐了naïve Bayes classifier。您应该实施此建议,因为该技术擅长根据显着特征​​进行分离。您提到了 while 关键字,但这不太可能有用,因为很多语言都使用它——贝叶斯分类器不会认为它有用。

      您的问题中一个有趣的部分是如何标记未知程序。空格分隔的块是一个不错的粗略开始,但要有意义地超越这将是棘手的。

      【讨论】:

      • 嗯,cmets 是帮助识别语言的方法之一。当然不是注释本身,而是用来告诉编译器它的注释的“关键字”。
      【解决方案4】:

      我认为你从错误的角度来处理这个问题。根据您的描述,听起来您正在构建一个分类器。一个好的分类器需要区分不同的类;它不需要精确估计输入和最可能的类之间的对应关系。

      实际上:您的分类器不需要精确评估某个输入与 C++ 的接近程度;它只需要确定输入是否更像 C 而不是 C++。这使您的工作变得更加轻松 - 您当前的大多数“未知”案例将接近一种或两种语言,即使它们没有超过您的基本阈值。

      现在,一旦您意识到这一点,您还将看到分类器需要什么训练:不是样本文件的某些随机方面,而是两种语言的不同之处。因此,当您解析了 C 示例和 C++ 示例时,您会看到 #include 并没有将它们分开。但是,classtemplate 在 C++ 中将更为常见。另一方面,#include 确实区分了 C++ 和 Java。

      除了关键字之外,当然还有其他方面可以使用。例如,最明显的是{ 的频率,而; 也有类似的区别。分类器的另一个非常有用的功能是不同语言的注释标记。基本问题当然是自动识别它们。同样,将///*'--#! 硬编码为伪关键字会有所帮助。

      这也确定了另一个分类规则:SQL 通常在一行的开头有--,而在 C 中它经常出现在其他地方。因此,您的分类器也可以将上下文考虑在内。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-20
        • 1970-01-01
        • 1970-01-01
        • 2011-01-19
        • 1970-01-01
        • 1970-01-01
        • 2016-04-22
        相关资源
        最近更新 更多