如何确定字符串是英文句子还是代码?

时间:2014-10-21 03:33:08

标签: java string nlp

考虑以下两个字符串,第一个是代码,第二个是英语句子(短语是准确的)。如何检测第一个是代码而第二个不是代码。

1. for (int i = 0; i < b.size(); i++) {
2. do something in English (not necessary to be a sentence).

我正在考虑计算特殊字符(例如&#34; =&#34;,&#34 ;;&#34;,&#34; ++&#34;等),并设置是否达到某个阈值。有没有更好的方法来做到这一点?任何Java库?

请注意,代码可能无法解析,因为它不是完整的方法/语句/表达式。

我的假设是英语句子非常规则,很可能只包含&#34;,&#34;,&#34;。&#34;,&#34; _&#34;,&#34 ;(&#34;,&#34;)&#34;等等。它们不包含这样的内容:write("the whole lot of text");

7 个答案:

答案 0 :(得分:4)

您可以尝试使用OpenNLP句子解析器。它返回一个句子的n个最佳解析。对于大多数英语句子,它至少返回一个。我相信,对于大多数代码片段而言,它不会返回任何代码片段,因此您可以确定它不是英语句子。

使用此代码进行解析:

    // Initialize the sentence detector
    final SentenceDetectorME sdetector = EasyParserUtils
            .getOpenNLPSentDetector(Constants.SENTENCE_DETECTOR_DATA);

    // Initialize the parser
    final Parser parser = EasyParserUtils
            .getOpenNLPParser(Constants.PARSER_DATA_LOC);

    // Get sentences of the text
    final String sentences[] = sdetector.sentDetect(essay);

    // Go through the sentences and parse each
    for (final String sentence : sentences) {
        // Parse the sentence, produce only 1 parse
        final Parse[] parses = ParserTool.parseLine(sentence, parser, 10);
        if (parses.length == 0) {
            // Most probably this is code
        }
        else {
            // An English sentence
        }
    }

这些是代码中使用的两个辅助方法(来自EasyParserUtils):

public static Parser getOpenNLPParser(final String parserDataURL) {
    try (final InputStream isParser = new FileInputStream(parserDataURL);) {
        // Get model for the parser and initialize it
        final ParserModel parserModel = new ParserModel(isParser);
        return ParserFactory.create(parserModel);
    }
    catch (final IOException e) {
        e.printStackTrace();
        return null;
    }
}

public static SentenceDetectorME getOpenNLPSentDetector(
        final String sentDetDataURL) {
    try (final InputStream isSent = new FileInputStream(sentDetDataURL)) {
        // Get models for sentence detector and initialize it
        final SentenceModel sentDetModel = new SentenceModel(isSent);
        return new SentenceDetectorME(sentDetModel);
    }
    catch (final IOException e) {
        e.printStackTrace();
        return null;
    }
}

答案 1 :(得分:3)

查看词法分析解析(就像编写编译器一样)。如果您不需要完整的陈述,则可能甚至不需要解析器。

答案 2 :(得分:2)

基本思想是将字符串转换为设置为标记。例如,上面的代码行可能变为&#34; KEY,SEPARATOR,ID,ASSIGN,NUMBER,SEPARATOR,......&#34;。然后我们可以使用简单的规则将代码与英语分开。

check out the code here

答案 3 :(得分:1)

您可以使用Java解析器或使用BNF创建一个,但问题在于您说代码可能无法解析,因此会失败。

我的建议:使用一些自定义正则表达式来检测代码中的特殊模式。使用尽可能多的成功率。

一些例子:

  • for\s*\((for loop)
  • while\s*\((while loop)
  • [a-zA-Z_$][a-zA-Z\d_$]*\s*\(constructor
  • \)\s*\{(块/方法的开头)
  • ...

是的它是一个很长的镜头,但看着你想要的东西,你没有多少可能性。

答案 4 :(得分:1)

没有必要重新发明轮子,编译器已经为你做了这个。任何编译过程的第一阶段都会检查文件中的标记是否在语言范围内。这当然不会对我们有所帮助,因为英语和java在这方面没有区别。然而,第二阶段,即合成分析,将使用任何英语形成的句子而不是java代码(或任何其他不合适的java)打印错误。因此,不使用外部库并尝试使用替代方法,为什么不使用已经可用的java编译器?

你可以有一个包装类,如

public class Test{

    public static void main(){

         /*Insert code to check here*/

    }

}

得到编译,如果它顺利然后屁股,你知道它是有效的代码。当然,它不适用于不完整的代码片段,例如你在没有结束括号的示例中放置的for循环。如果它编译得不好,你可以用可能的方式威胁字符串,例如尝试用你自己的用flex-bison制作的自制的伪英语合成分析器来解析它,例如GNU用于制作GCC的工具。我不知道你想要用你想要制作的程序到底想要完成什么,但是这样你就可以知道它是代码,手工制作的英文句子,还是你不应该关心的垃圾。解析自然语言真的很难,现在现代方法使用不准确的statitiscal方法,所以它们并不总是正确的,你可能不希望在你的程序中。

答案 5 :(得分:1)

对于一个非常简单的方法,似乎在某些样本上运行良好。取出System.out。它仅用于说明目的。正如您从示例输出中看到的那样,代码注释看起来像文本,因此如果将大的非javadoc块注释混合到代码中,您可能会得到误报。硬编码的阈值是我的估计。随意微调它们。

public static void main(String[] args) {
    for(String arg : args){
        System.out.println(arg);
        System.out.println(codeStatus(arg));
    }
}

static CodeStatus codeStatus (String string) {
    String[] words = string.split("\\b");
    int nonText = 0;
    for(String word: words){
        if(!word.matches("^[A-Za-z][a-z]*|[0-9]+(.[0-9]+)?|[ .,]|. $")){
            nonText ++;
        }
    }
    System.out.print("\n");
    double percentage = ((double) nonText) / words.length;
    System.out.println(percentage);
    if(percentage > .2){
        return CodeStatus.CODE;
    }
    if(percentage < .1){
        return CodeStatus.TEXT;
    }
    return CodeStatus.INDETERMINATE;
}

enum CodeStatus {
    CODE, TEXT, INDETERMINATE
}

示例输出:

You can try the OpenNLP sentence parser. It returns the n best parses for a sentence. For most English sentences it returns at least one. I believe, that for most code snippets it won't return any and hence you can be quite sure it is not an English sentence.

0.0297029702970297
TEXT
Use this code for parsing:

0.18181818181818182
INDETERMINATE
    // Initialize the sentence detector

0.125
INDETERMINATE
    final SentenceDetectorME sdetector = EasyParserUtils
            .getOpenNLPSentDetector(Constants.SENTENCE_DETECTOR_DATA);

0.6
CODE
    // Initialize the parser

0.16666666666666666
INDETERMINATE
    final Parser parser = EasyParserUtils
            .getOpenNLPParser(Constants.PARSER_DATA_LOC);

0.5333333333333333
CODE
    // Get sentences of the text

0.1
INDETERMINATE
    final String sentences[] = sdetector.sentDetect(essay);

0.38461538461538464
CODE
    // Go through the sentences and parse each

0.07142857142857142
TEXT
    for (final String sentence : sentences) {
        // Parse the sentence, produce only 1 parse
        final Parse[] parses = ParserTool.parseLine(sentence, parser, 10);
        if (parses.length == 0) {
            // Most probably this is code
        }
        else {
            // An English sentence
        }
    }

0.2537313432835821
CODE
and these are the two helper methods (from EasyParserUtils) used in the code:

0.14814814814814814
INDETERMINATE
public static Parser getOpenNLPParser(final String parserDataURL) {
    try (final InputStream isParser = new FileInputStream(parserDataURL);) {
        // Get model for the parser and initialize it
        final ParserModel parserModel = new ParserModel(isParser);
        return ParserFactory.create(parserModel);
    }
    catch (final IOException e) {

0.3835616438356164
CODE

答案 6 :(得分:0)

Here是一个完美而安全的解决方案。基本思想是首先获取所有可用的关键字和特殊字符,然后使用set to builder一个标记生成器。 例如,问题中的代码行变为&#34; KEY,SEPARATOR,ID,ASSIGN,NUMBER,SEPARATOR,......&#34;。然后我们可以使用简单的规则将代码与英语分开。