简单可靠地检测文本代码的方法?


142

GMail具有此功能,如果您尝试发送它认为可能带有附件的电子邮件,它将向您发出警告。

您是要附加文件吗?

由于GMail检测到see the attached电子邮件中的字符串,但没有实际附件,因此当我单击“发送”按钮时,它会通过“确定” /“取消”对话框警告我。

我们在堆栈溢出方面有一个相关的问题。也就是说,当用户进入后像这样的

我的问题是我需要更改数据库,但我不会创建 
一个新的连接。例:

数据集dsMasterInfo = new DataSet();
数据库db = DatabaseFactory.CreateDatabase(“ ConnectionString”);
DbCommand dbCommand = db.GetStoredProcCommand(“ uspGetMasterName”);

该用户未将其代码格式化为代码!

也就是说,他们没有为每个Markdown缩进4个空格,也没有使用代码按钮(或键盘快捷键ctrl+ k)为他们这样做。

因此,我们的系统正在接受很多编辑,人们必须进入这些编辑区域,并手动为无法解决该问题的人们设置代码格式。这导致很多肚皮舞。我们已经多次改善了编辑器的帮助,但是由于没有赶到用户家并为他们按下键盘上的正确按钮,我们无所适从,不知道下一步该怎么做。

这就是我们考虑使用Google GMail样式警告的原因:

您是要发布代码吗?

您编写了我们认为看起来像代码的内容,但是没有使用工具栏代码按钮或ctrl+ k代码格式化命令通过缩进4个空格来将其格式化为代码。

但是,提出此警告要求我们检测问题中是否存在我们认为未格式化的代码。一种简单,半可靠的方法是什么?

  • 根据Markdown的规定,代码总是缩进4个空格或在反引号内,因此任何格式正确的代码都可以立即从支票中丢弃。
  • 这仅是警告,并且仅适用于声誉低下的用户提出第一个问题(或提供其第一个答案),因此,只要它们的错误率在5%或以下,就可以接受一些误报。
  • 关于堆栈溢出的问题可以使用任何语言,尽管实际上可以将检查范围限制为“十大”语言。每个标记页面都是C#,Java,PHP,JavaScript,Objective-C,C,C ++,Python,Ruby。
  • 使用Stack Overflow Creative Commons数据转储来审核您可能的解决方案(或仅在Stack Overflow 的前10个标签中选择几个问题),然后查看其效果。
  • 伪代码很好,但是如果您想变得更加友好,我们可以使用c#。
  • 越简单越好(只要可行)。吻!如果您的解决方案需要我们尝试用10种不同的编译器来编译帖子,或者需要一群人来手动训练贝叶斯推理引擎,那...就不完全是我们的初衷。

34
我认为,如果仅在没有缩进的情况下始终显示警告,那么您将远远低于5%的错误限制。这只是开玩笑的一半。
康拉德·鲁道夫

59
@Konrad如果出现以下消息,则效果会更好:“或者您的问题是缺少有助于他人理解的代码示例,或者您忘记了对其进行适当的缩进”。这应该涵盖所有案例的99%。
thorstenmüller2011年

3
这是一个很好的问题,但我觉得没有答案。您向我展示了一个防止白痴的系统,我将向您展示一个更好的白痴。即使CODE可以解决此问题,也许也不应该吗?正是这些无知的人不厌其烦地问一个正确的问题,正在为像我这样提出正确问题并做出正确答案的人提供帮助。
maple_shaft

2
我见过的一个常见模式是本身已适当缩进的代码块,但其中的第一行和最后一行(通常只有这两行,例如,在显示多个功能时有时会更多)未标记为代码。这可能也应该被检测到。
3Doubloons 2011年

3
附带一提,GMail确认文本相当混乱。如果您对第一个问题的回答是“是”,那么第二个问题的答案是“否” ...
pimvdb 2011年

Answers:


147

一个适当的解决方案可能是一些学习/统计模型,但是这里有一些有趣的想法:

  1. 行尾的分号。仅此一项就可以捕获一大堆语言。
  2. 直接在文本后加括号,没有空格将其分开: myFunc()
  3. 两个单词之间的点或箭头: foo.bar = ptr->val
  4. 花括号,方括号的存在: while (true) { bar[i]; }
  5. 存在“注释”语法(/ *,//等): /* multi-line comment */
  6. 不常见的字符/运算符: +, *, &, &&, |, ||, <, >, ==, !=, >=, <=, >>, <<, ::, __
  7. 在文本上运行语法荧光笔。如果最终以高比例突出显示它,则可能是代码。
  8. 帖子中的驼峰文本。
  9. 嵌套的括号,大括号和/或括号。

可以跟踪每一个出现的次数,并且可以将它们用作机器学习算法(如感知器)中的功能,就像SpamAssassin那样。


25
提示:3的权重很低,因为单词之间的点可能是拼写错误的结果。5个不应该匹配的URL。对于6,在代码上下文之外也经常使用&符,这也可能使该字符的权重降低。再次检查荧光笔是否正常工作,因为它可以突出显示非代码文本,正如我有时在Notepad ++中看到的那样。
Tamara Wijsman

8
重新。作为错别字-标记作者应该进行编辑不会有任何危害。
user151019 2011年

4
此外,很多语言都可以帮助特定的关键字:WHILE,否则,如果,LOOP,BREAK等
JoséNunoFerreira

6
在非数字词之前添加$的用法:$ var在Perl和PHP(和Ruby?)中很常见。
PhiLho 2011年

4
你不会发现我的SELECT DISTINCT name FROM people WHERE id IS NOT NULL
Benoit

54

我很想知道一方面的书面英语平均水平和另一方面的代码平均水平是多少。

  • 段落长度
  • 线长
  • 字数
  • 使用的字符
  • 字母,数字和其他符号字符之间的比率
  • 每个单词的符号数
  • 等等

也许仅此一项就可以区分代码和其余代码。至少我相信,无论哪种语言,代码在许多情况下都会显示出一些明显不同的指标。

好消息是:您已经有大量数据可用来建立统计数据。


好的,我提供了一些数据来支持我的假设。:-)

我对您自己的帖子以及在StackOverflow上找到的第一篇帖子进行了快速而肮脏的测试,并使用了一个非常高级的工具:wc

这是wc在这两个示例的文本部分和代码部分上运行后的结果:

首先让我们看一下英语部分

  • 帖子的英文部分(2635个字符,468个单词,32行)
    • 5个字符/字,82个字符/行,14个字/行
  • 其他帖子的英语部分(1499个字符,237个单词,12行)
    • 6个字符/字,124个字符/行,19个字/行

你觉得很相似吗?

现在让我们看一下代码部分

  • 帖子的代码部分(174个字符,13个单词,3行)
    • 13个字符/字,58个字符/行,4个字/行
  • 其他帖子的代码部分(4181个字符,287个单词,151行)
    • 14个字符/字,27个字符/行,2个字/行

看看这些指标有多大不同,但更重要的是,它们与英文指标有多大不同?这只是使用有限的工具。现在,我相信您可以通过测量更多指标来获得真正准确的信息(我特别考虑的是字符统计信息)。

我可以饼干吗?


6
行长,特别是如果您排除项目符号点并寻找小于特定长度且包含特定标点符号的聚集行,则似乎是一个不错的选择。
乔恩·霍普金斯

这将适用于代码块,但查找内嵌cdde似乎要困难得多。不过,不确定到底有多重要-更大的问题是反格式代码的大块。
cHao 2011年

3
没有饼干。在您的文章链接为404
james.garriss

@ james.garriss:互联网偷了我的饼干罐。:(感谢您的通知,但。
朱利安Guertault

23

通常,马尔可夫链用于生成文本,但是它们也可以用于预测文本(根据CE Shannon 1950)与训练模型的相似性。我建议使用多个马尔可夫链。

对于每种流行的语言,在该语言的大型代表性代码样本上训练马尔可夫链。然后,对于您要检测其代码的Stack Overflow帖子,对每个链执行以下操作:

  • 在帖子中循环浏览。
    • 声明两个变量:ACTUAL = 1.0和HIGHEST = 1.0
    • 循环浏览该行中的每个字符。
      • 对于每个字符,在马尔可夫链中找到当前字符是前N个字符之后的概率。设置ACTUAL = ACTUAL * PROB 1。如果当前字符不在链中,则对PROB 1使用一个很小的值,例如0.000001。
      • 现在,找到最有可能跟随前N个字符的字符(即,最高概率)。设置HIGHEST = HIGHEST * PROB 2
      • 显然,PROB 2 > = PROB 1

对于每一行,您应该有一个ACTUAL和一个HIGHEST值。用ACTUAL除以HIGHEST。这将为您提供关于特定行是否为源代码的适用性评分。这会将数字与您给出的示例中的每一行相关联:

my problem is I need to change the database but I don't won't to create // 0.0032
a new connection. example: // 0.0023

DataSet dsMasterInfo = new DataSet(); // 0.04
Database db = DatabaseFactory.CreateDatabase("ConnectionString");   // 0.05
DbCommand dbCommand = db.GetStoredProcCommand("uspGetMasterName");  // 0.04

最后,您需要选择一个阈值来确定帖子中何时有代码。这可能只是通过观察选择的可以产生高性能的数字。它还可以考虑得分较高的行数。

训练

为了训练,采购该语言的大量代表性代码示例。编写一个程序来遍历代码文本,并将文件中的每个N-gram(N的范围应参数化)与后续字符的统计频率相关联。这将产生跟随双字母组的字符的多个可能状态,每个状态与一个概率相关联。例如,二元组“()”可能具有以下某些字符概率:

"()" 0.5-> ";"
"()" 0.2-> "."
"()" 0.3-> "{"

应该将第一个读为,例如“分号跟随空括号的概率为0.5。”

对于训练,我建议使用N克大小为2到5的N克。回到我对此进行一些研究时,我们发现N-gram大小为2到5的英语非常有效。由于大多数源代码都像英语一样,因此建议您从该范围开始,然后在找到可行的方法时进行调整以找到最佳的参数值。

一个警告:模型将受到标识符,方法名称,空格等的影响。但是,您可以调整训练以忽略训练样本的某些功能。例如,您可以折叠所有不必要的空格。输入中的空白(Stack Overflow帖子)也可以忽略。您也可以忽略字母大小写,这在面对不同的标识符命名约定时会更具弹性。

研究过程中,我们发现我们的方法对西班牙语和英语均适用。我不明白为什么这对于源代码也不能很好地起作用。源代码比人类语言更加结构化和可预测。


2
我预见的唯一问题是,概率将大大小于玩具示例中的概率。给定数值不稳定性,这意味着很快所有概率都为0。但是,使用对数赔率可以解决此问题。此外,我会使用较大的标记(即不是字符,而是单词/标点符号)。
Konrad Rudolph

2
@Konrad:这里的想法不是测试绝对概率:是测试相对概率。对于每一行,该行的文本更有可能是由英语语言模型还是由代码语言模型生成的。
肯·布鲁姆

5
您可以在现有的SO帖子上训练该模型(特别是因为您可能需要考虑Markdown语法)。如果您假设大多数帖子的格式正确(或者您从数以万计的数量中挑选了大量帖子,以删除格式不正确的帖子),那么您会认为未编码格式的内容是英文文本,并且代码格式化的东西是代码,您可以从实际的SO答案中进行训练。
肯·布鲁姆

1
LingPipe的网站上提供了有关如何执行此操作的教程(在Java中使用LingPipe)。在本教程的最后,有许多关于解决此问题的技术的论文。我建议阅读它们。
肯·布鲁姆

1
有趣的是,最新解决方案的投票数非常低,而且评分远远低于所有临时解决方案,这些解决方案虽然可能足够好,但在很大程度上依赖于特殊情况,并且固有地就可以了,容易过拟合。
康拉德·鲁道夫

13

我可以建议一种根本不同的方法吗?在SO上,唯一允许的人工语言是英语,因此非英语的任何东西都有99.9%的机会成为代码段

因此,我的解决方案是:使用许多英语检查器之一(只需确保它们还发出信号-除了拼写错误以外-语法错误,如双点,或非语言符号,如#~)。然后,任何引发大量错误和警告的行/段落都应触发“此代码是吗?” 题。

当然,对于使用其他英语以外的其他语言的StackExchange网站,也可以采用这种方法。

只是我的2美分...


16
问题在于,很多传入的问题也不是英语(尽管它们很像)。
布伦丹·朗·

3
@Brendan-然后增加了此建议的优势:在帖子中可能打算成为英文的部分加下划线(或突出显示)中的错误,并帮助作者用英语写……!;)
mac

1
我是荷兰人,我编写的所有代码都是英文,通过注释不是(取决于项目)。因此,非英语必须是代码不足的。那或您的意思是,破损的英语必须是代码。
伊沃·利门

@Ivo-我的评论是开玩笑地针对破碎的英语问题!;)不过,我要说的是,在另一种语言我的建议意见也只是正常工作... OTOH 阻断英文注释不会触发“是这个代码?” 问题,但这很好,因为为其编写注释的代码已经触发了它……
mac

11

我可能会为此获得一些反对,但我认为您是从错误的角度来解决这个问题。

这行让我:

人们必须走进去并且手动格式化那些以某种方式无法弄清楚这一点的人的代码

IMO认为立场有点自大。我在软件设计中发现了很多东西,当问题不是用户而是软件本身(或至少是UI)时,程序员和设计师会因为无法弄清楚如何正确使用软件的用户而烦恼。

造成此问题的根本原因不是用户,而是他们可以做到这一点对他们而言并不明显。

如何更改UI以使其更明显?当然,这将是:

  1. 对新用户而言,确切的是他们需要做什么
  2. 您可以轻松构建而不是编写复杂的算法来检测多种语言的代码逻辑

例:

在此处输入图片说明


26
实际上,此IMO提出了一些很糟糕的问题,例如“我有问题,请帮助我,代码在下面”-很少需要将代码与问题分开。最好的问题是这样的:“我想实现这一点,并编写了这两行代码,但是效果却出在下面,这是什么问题”-很少有代码与普通语言相互交错。
sharptooth 2011年

4
您的根本观察是正确的,但您的诊断仍然是错误的:实际上,Jeff 正在尝试通过这种方法来改善用户界面。此外,当前的UI已经经历了多个周期,尽管我毫不怀疑它可以得到改进(大幅度地提高),但我怀疑这将有助于防止懒惰的白痴。您提出的解决方案也不会。@sharptooth已对此进行了说明。
Konrad Rudolph

2
我会考虑开箱即用+1,但我不同意具体建议,因为张贴“支持代码”会迫使问题流变得不自然。我从来没有在问题的底部抛弃过代码。我几乎总是发布简介,示例代码,然后是实际问题。如果您接受内联代码必不可少的前提,则需要某种类型的格式设置-格式设置必须由用户输入或由系统建议。而这正是杰夫要问的事情。
妮可(Nicole)

1
@Konrad:除了我的上述评论和对您的回应之外,我不认为Jeff通过采取这种方法来改善UI,而只是处理潜在问题的症状。如果对UI进行了改进,以至于不会犯错误,那么就不需要警告用户的解决方案。我毫不怀疑我的例子是最终的解决方案,但有一个问题需要考虑到一个问题:“我们是否以最好的方式提出这一问题?”。
matt_asbury 2011年

1
简单的句子,请使用{}文本框周围的按钮标记代码即可
圣保罗Ebermann

11

伪代码会带来真正的挑战,因为所有编程语言都依赖于特殊字符,例如'[]',';','(()'等)。只需简单地计算这些特殊字符的出现即可。就像检测二进制文件一样(样本的5%以上包含字节值0)。


我将改善这些效果,就像将这些特殊字符组成一组一样,例如[](); {} =。每行包含超过2-3个这些组的代码行。
Honza 2011年

...并寻找最常用语言的常用字符串,例如“ = someword();” 对于大多数花括号语言,类似XML的语法(例如“ <something>”和“ <ab:cde>”)以及其他语言的其他常见字符串。我确实相信某种通用语法的查找表将是一个很好的解决方案,因为当您发现要实现的新语言时可以对其进行扩展。
2011年

您可能应该删除伪代码。有些人喜欢以C风格的语言编写它,但另一些人会使用纯英语,并且看起来更接近VB6
James P.

4

我认为您可能只需要针对特定​​的语言,一般来说,这个问题很棘手,因为您可以获得与英语非常相似的语言(例如notify7)。但幸运的是,最常用的那些可以轻松覆盖。

我的第一个切入点是寻找序列“; \ n”,它将使您与C,C ++,Java,C#和其他使用相似语法且非常简单的语言很好地匹配。与英文相比,它也不太可能用英文; 没有换行符


也许还有大量的花括号; p
马克·格雷夫

1
就像Je​​ff在他的帖子中说的那样,它们可能只会针对主要语言。在任何情况下,我怀疑是新用户(对他们来说,这个功能是意)会更容易发布比,也就是说,INTERCAL C#或Javascript ;-)

是的,但这不适用于编程语言BRAINFUCK或BLANK。;-)
Ivo Limmen 2012年

4

有人提到先查看标记,然后再寻找语法,但是由于针对新用户而被拒绝了。

更好的解决方案是在问题正文中查找语言名称,然后应用相同的策略。如果我提到“ Javascript”,“ Java”或“ C#”,那么问题就出在这里,问题中的代码很可能就是该语言。


特别是如果标题是“ vb c#.net dot net帮我救救我!”
NickAldwin 2011年

1

首先,通过拼写检查运行它,它将发现很少的正确英语单词,但是应该有很多单词会被拼写检查器建议拆分。

然后有一些标点符号/特殊字符,对于普通英语来说不是典型的,对于代码来说很典型:

  • something(); 只是不能说简单的英语;
  • $something这里something是不是所有的数字;
  • -> 没有空格的单词之间;
  • . 没有空格的单词之间;

当然,要使其运行良好,您可能希望在这些特征的基础上构建贝叶斯分类器。


1
检测包含()的非缩进行;将是建议该消息的一个很好的理由。

粘贴代码之前不会拼写什么拼写检查器?
Tim Post

有了非母语英语作者写的一些信息,拼写检查器将使其他所有单词都窒息...
PhiLho 2011年

@Ph:这些问题/答案无论如何都不会被接受。
vartec

1

有几种语言共享相似的语法。大多数语言受几种语言的影响,因此[AMPL,AWK,csh,C ++,C-,C#,Objective-C,BitC,D,Go,Java,JavaScript,Limbo,LPC,Perl,PHP, Pike,Processing [都受C的影响,因此,如果您检测到C,则可能会检测到所有这些语言。因此,您只需编写一个简单的模式即可检测该语言集。

我也会将文本拆分为块,因为大多数代码将由两个换行符或与帖子中其他文本块相似的代码拆分。

这可以使用javascript(C系列的一个非常简单的不完整示例)轻松完成:

var txt = "my problem is I need to change the database but I don't won't to create a new connection. example:\n\nDataSet dsMasterInfo = new DataSet();Database db = DatabaseFactory.CreateDatabase(&quot;ConnectionString&quot;);DbCommand dbCommand = db.GetStoredProcCommand(&quot;uspGetMasterName&quot;);";
var blocks = txt.split(/\n\n/gi); console.dir(blocks);
var i = blocks.length;
var cReg = /if\s*\(.+?\)|.*(?:int|char|string|short|long).*?=.+|while\s*\(.+?\)/gi;

while ( i-- ){
   var current = blocks[i];
   if ( cReg.test( current ) ){
      console.log("found code in block[" +  i + "]");
   }
}

0

只需为每一行计算单词/标点符号。英语将趋向于4或更多,而代码则少于2。

例如,上面的段落有18个单词和4个标点符号。本段有19个单词和4个标点符号,因此不超出预期。

当然,这需要针对英语能力较差的演讲者的新问题进行测试,并且可能是在这种情况下,统计数据存在偏差。

我希望[non-whitespace]。[whitespace或newline]在代码中非常少见,但在英语中很常见,因此可以将其视为单词,而不是标点符号。

我认为最大的问题将是内联代码,其中有人问如下问题:

如果我说(i = 0; i> 100; i ++){}是什么意思?

这是代码和英文,应标有反引号:

如果我说for (i=0; i>100; i++) {}那是什么意思?


0

我认为您应该首先区分仅需要实际指定的(足够)格式的代码和(仍然)需要手动格式化的(太)格式差的代码。

格式化的代码具有断行和缩进。那就是:如果一行之前有一个单独的换行符,那么您就有一个不错的候选人。如果最重要的是空格,那么您将是一个很好的候选人。

普通文本使用两个换行符或两个空格以及一个换行符进行格式设置,因此有一个明确的区分标准。

在LISP代码中找不到分号,在Ruby代码中可能找不到括号,在伪代码中可能根本找不到。但是,在任何(非深奥的)语言中,您都会发现体面的代码将使用断行和缩进进行格式化。没有什么比这更普遍了。因为最终代码是写给人类阅读的。

因此,首先,搜索潜在的代码。同样,代码行通常成组出现。如果您有一个,那么上面或下面的代码也很有可能也是一行代码。

找出潜在的代码行之后,就可以根据可量化的标准对其进行检查,并选择一些阈值

  • 非单词字符的频率
  • 标识符的频率:使用CamelCase或under_score样式的非常短的单词或非常长的单词
  • 重复不常见的单词

同样,由于现在有程序员和CS,stackoverflow的范围明显缩小了。人们可能会考虑将所有语言标签表示为语言。在发布时,系统会要求您至少选择一种语言标签,选择该language-agnostic标签或明确省略它。

在第一种情况下,您知道要查找的语言;在第二种情况下,您可能要寻找伪代码;在最后一种情况下,可能不会有任何代码,因为这是与某些技术或技术有关的问题。框架之类的。


0

您可以为要检测的每种语言创建一个解析器(通常很容易找到ANTLR的语言定义),然后在每个解析器中运行问题的每一行。如果任何行都能正确解析,则您可能有代码。

这样做的问题是,某些英语(自然语言)句子可能会解析为代码,因此您可能还希望包含其他一些构想,或者只有在正确地解析出多于一两个连续的行时,才可以限制肯定的结果相同的语言解析器。

另一个潜在的问题是,这可能不会获取伪代码,但这可能没问题。


人们通常在他们的代码中有语法错误(并对此进行询问)。
圣保罗Ebermann

0

从长远来看,什么可能是最有前瞻性的,并且需要最少的手动调整,因为其他语言(看起来与现在使用最多的编程语言有所不同)会变得越来越流行,而当前使用的语言则变得不那么流行了。类似于Google Translate的功能(请参见标题为“它如何工作?”的段落),而不是查找诸如ab和a()等特定内容。

换句话说,计算机可以自行解决它,而不是手动思考要查找的代码中的模式。这可以通过让

  1. 许多不同编程语言的大量代码

    • 建议:自动从基于Web的源代码存储库(例如Google Code或Github),甚至从Stackoverflow上已经标记为代码的内容中获取代码示例

    • 注意:解析代码注释可能是一个好主意

  2. 大量英文文章摘自网络文章

    • 尽管不是来自有关编程的文章(否则它们中可能包含代码并将系统混在一起:-))

并让某种算法自动在代码中查找非英语的模式,反之亦然,然后通过在帖子上运行算法,使用这些模式来检测什么是代码,什么不是代码。

(但是,我不确定这样的算法将如何工作。当前问题的其他答案可能对此有有用的信息。)

然后,系统可以每隔一段时间重新扫描一次代码,以说明该时间点代码的外观发生了变化。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.