好吧,我已经解决这个问题好几个星期了,我有一个程序可以读取一个文件,其中包含来自迷你语言的一些代码,读取并打印每个令牌,其中包含令牌的描述。这个迷你语言的一部分是它支持单行和多行注释的能力。
注释的正则表达式是{[^}]*}
,意思是:
- 注释以大括号
{
开头 - 后面跟0个或多个除大括号
[^}]*
之外的任何字符 - 后跟一个大括号,结束注释
}
旁注:注释不能嵌套,这意味着如果我有一个注释(如{This is a {nested} comment}
),则不会被视为有效的注释,因为它只能有一个大括号。尽管如此,像{This is another {comment}
这样的注释是有效的,因为只有一个大括号
在测试这个程序时,我遇到了一个问题,我的程序会读取一个文件,并遇到一个多行注释,但程序不能将注释识别为多行,而是打印出注释内部的内容,而不是整个注释本身。我花了整整一周或一周半的时间试图让它发挥作用。我尝试了各种正则表达式的组合以及if
语句的放置位置,但都没有找到解决方案。我已经尽了一切努力来修复它,但由于我对正则表达式没有太多经验,我一定错过了一些非常明显的东西。
这里我有一段代码
旁注:我让我的程序通过另一个类中的用户输入来接受文件名。
import java.io.*;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Analyzer {
public void lex(String filename) {
try {
Scanner scanFile = new Scanner(file);
while(scanFile.hasNextLine()) {
String str = scanFile.nextLine();
String keyword = "(\bWHILE\b|\bENDWHILE\b|\bIF\b|\bENDIF\b|\bPRINT\b)";
String comment = "(\{[^\}]*\})";
String literal = "(\b[0-9]+\b)";
String identifier = "(\b[a-z]+\b)";
String symbol = "((\()|(\))|(;))";
String operator = "((\+)|(\-)|(\*)|(/)|(\=)|(\<)|(\:\=))";
String keywordERROR = "(PRINT\w+)";
String commentERROR = "(\{.*\}.*\})";
String literalERROR = "([0-9]+[a-zA-Z_]+)";
String identERROR = "([a-z]+[A-Z_0-9]+)";
String alphabetERROR = "(~|`|\!|@|#|\$|%|\^|\&|_|\||\:|'|"|\?|\>|\.|\,|\\)";
String regex = keyword + "|" + keywordERROR + "|" + comment + "|" + commentERROR + "|" + literal + "|" + literalERROR
+ "|" + identifier + "|" + identERROR + "|" + symbol + "|" + operator + "|" + alphabetERROR;
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
while(matcher.find()) {
if(matcher.group(1) != null)
System.out.println(matcher.group(1) + "tKeyword");
else if(matcher.group(2) != null)
System.out.println(matcher.group(2) + "tError");
if(matcher.group(3) != null)
System.out.println(matcher.group(3) + "tComment");
else if(matcher.group(4) != null)
System.out.println(matcher.group(4) + "tError");
if(matcher.group(5) != null)
System.out.println(matcher.group(5) + "tLiteral");
else if(matcher.group(6) != null)
System.out.println(matcher.group(6) + "tError");
if(matcher.group(7) != null)
System.out.println(matcher.group(7) + "tIdentifier");
else if(matcher.group(8) != null)
System.out.println(matcher.group(8) + "tError");
if(matcher.group(9) != null) {
if(matcher.group(10) != null)
System.out.println(matcher.group(10) + "tOpen Parenthesis");
if(matcher.group(11) != null)
System.out.println(matcher.group(11) + "tClose Parenthesis");
if(matcher.group(12) != null)
System.out.println(matcher.group(12) + "tSemi-colon");
}
if(matcher.group(13) != null) {
if(matcher.group(14) != null)
System.out.println(matcher.group(14) + "tAddition Operator");
if(matcher.group(15) != null)
System.out.println(matcher.group(15) + "tSubtraction Operator");
if(matcher.group(16) != null)
System.out.println(matcher.group(16) + "tMultiplication Operator");
if(matcher.group(17) != null)
System.out.println(matcher.group(17) + "tDivision Operator");
if(matcher.group(18) != null)
System.out.println(matcher.group(18) + "tEquality Comparison Operator");
if(matcher.group(19) != null)
System.out.println(matcher.group(19) + "tLess Than Operator");
if(matcher.group(20) != null)
System.out.println(matcher.group(20) + "tAssignment Operator");
}
if(matcher.group(21) != null)
System.out.println(matcher.group(21) + "tError");
}
}
scanFile.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
正如我之前所说,我已经尝试了许多不同的方法来解决这个问题。我尝试过的一些事情是添加这样的返回序列:{[^}]*[rn]*}
、{[rn]*[^}]*}
、{[rn]*[^}]*[rn]*}
、{[^}]*s*}
、{s*[^}]*s*}
、(?s){[^}]*}
和(?m){[^}]*}
,尝试为我的Pattern对象使用DOTALL
和MULTILINE
标志,只是在寻找我能找到的任何教程,但我没有找到任何运气。
我正在读取的文件如下:
{This is
a multi-line
comment.}
WHILE(x<10)
PRINT x;
x:=x+2;
ENDWHILE
输出应该是这样的:
{This is a multi-line comment} Comment
WHILE Keyword
( Open Parenthesis
x Identifier
< Less Than Operator
10 Literal
) Close Parenthesis
PRINT Keyword
x Identifier
; Semi-colon
x Identifier
:= Assignment Operator
x Identifier
+ Addition Operator
2 Literal
; Semi-colon
ENDWHILE Keyword
但相反,输出看起来是这样的:
is Identifier
a Identifier
multi Identifier
- Subtraction Operator
line Identifier
comment Identifier
. Error
WHILE Keyword
( Open Parenthesis
x Identifier
< Less Than Operator
10 Literal
) Close Parenthesis
PRINT Keyword
x Identifier
; Semi-colon
x Identifier
:= Assignment Operator
x Identifier
+ Addition Operator
2 Literal
; Semi-colon
ENDWHILE Keyword
我不确定我做错了什么。非常感谢您的帮助!
您可以在循环时使用另一个继续读取文件,如果您的行以大括号开头,但没有以大括号结尾,则如下所示:
while(scanFile.hasNextLine()) {
String str = scanFile.nextLine().trim(); // trim off indents etc.
// If the line is blank just read in the next line.
if (str.equals("")) { continue; }
// If this is a multi-line comment then
if (str.startsWith("{") && !str.endsWith("}")) {
while(scanFile.hasNextLine()) {
String commentStr = scanFile.nextLine().trim();
str+= " " + commentStr;
if (commentStr.endsWith("}")) { break; }
}
}
// Do the rest of your processing....
// ..................................
// ..................................
}
另一方面。。。。我不会使用RegEx来解析这个文件内容,但也许出于某种原因你需要这样做。无论如何,良好的RegEx练习。:)
由于Java的Pattern
(用于正则表达式)默认禁用了MULTILINE
模式,因此代码无法工作。
尝试在正则表达式字符串的开头使用(?m)
启用它。或者以其他方式将Pattern
的配置设置为使用MULTILINE。
AFAICS{[^}]*}
正则表达式没有任何(其他)问题,尽管您可能可以使用{.*?}
,它的可读性稍高。