考虑以下两个字符串,第一个是代码,第二个是英语句子(短语是准确的)。如何检测第一个是代码而第二个不是代码。
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");
答案 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;。然后我们可以使用简单的规则将代码与英语分开。
答案 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;。然后我们可以使用简单的规则将代码与英语分开。