我很难在字符串中获取正确的标记。我只能接受诸如(假,真,或,而不是),())之类的令牌。如果字符串中的标记是“(false”,那么我需要同时返回“(”和“false”。这是我遇到问题的地方。
例如,我想要的输出是:
line: [ not (false or error true) ]
next token: [not]
next token: [(]
next token: [false]
next token: [or]
next token: [true]
next token: [)]
但我的输出是:
line: [ not (false or error true) ]
next token: [not]
next token: [(]
next token: [or]
next token: [true]
next token: [)]
在迭代扫描下一个“或”标记时,我之前已经返回“(”并且我的下一个标记是“假”,但我无法弄清楚如何返回它。它跳过它并返回“或”
以下是我的方法。
public boolean hasNext() {
if(!scan.hasNext()){
return false;
}
return true;
}
public String next() {
while(scan.hasNext()){
scan.useDelimiter(" ");
otherToken = scan.next();
if(otherToken.contains("(") || otherToken.contains(")")){
if(otherToken.contains("(")){
nextToken = otherToken.substring(1, otherToken.length());
return "(";
}
if(otherToken.contains(")")){
nextToken = ")";
return otherToken.substring(0, otherToken.length()-1);
}
}
if(otherToken.equals("true") || otherToken.equals("false") ||
otherToken.equals("or") || otherToken.equals("and") ||
otherToken.equals("not")){
nextToken = otherToken;
return nextToken;
}
if(otherToken.equals("(") || otherToken.equals(")")){
nextToken = otherToken;
return nextToken;
}
else{
continue;
}
}
return nextToken;
}
答案 0 :(得分:1)
通过稍微调整分隔符正则表达式模式,您可以让java Scanner返回您想要的标记:
String line =" not (false or error true) ";
Scanner scan = new Scanner(line);
scan.useDelimiter(
"(?<=(?:\\b(?:false|true|or|and|not)\\b)|[()]|^)" // lookbehind
+".*?" // non-greedy match all
+"(?=(?:\\b(?:false|true|or|and|not)\\b)|[()]|$)"); // lookahead
while(scan.hasNext()) {
System.out.format("next token: [%s]%n", scan.next());
}
<强>输出:强>
下一个标记:[不]
下一个标记:[(]
下一个标记:[false]
下一个标记:[或]
下一个标记:[true]
下一个标记:[)]
但是,使用正则表达式自行查找令牌会更简单:
String line = "not (false or error true)";
Pattern p = Pattern.compile("(?:\\b(?:false|true|or|and|not)\\b)|[()]");
Matcher m = p.matcher(line);
while(m.find()) {
System.out.format("next token: [%s]%n", m.group());
}
答案 1 :(得分:0)
您正在使用空格作为分隔符。这是为您的字符串“not(false或error true)”
创建的标记列表第二个标记是“(false”。以下代码返回“(”如果遇到包含“(”的字符串:
if(otherToken.contains("(") || otherToken.contains(")")){ // STRING (false CONTAINS (
if(otherToken.contains("(")){ // IF STRING CONTAINS ( WHICH (FALSE DOES
nextToken = otherToken.substring(1, otherToken.length()); // NOT SURE WHERE nextToken IS USED.
return "("; // RETURN "("
}
if(otherToken.contains(")")){ // EVEN IF TOKEN IS
nextToken = ")";
return otherToken.substring(0, otherToken.length()-1);
}
}
答案 2 :(得分:0)
别介意令牌化,有split()
的单行解决方案:
String[] tokens = input.replaceAll("^.*?(?=[()]|\\b(or|not|true|false)\\b)|((?![()]|\\b(or|not|true|false)\\b).)*$", "")
.split("((?<=[()])|(?<=\\bor\\b)|(?<=\\bnot\\b)|(?<=\\btrue\\b)|(?<=\\bfalse\\b)).*?((?=[()]|\\b(or|not|true|false)\\b|$))");
请参阅live demo。
首先删除任何前导或尾随垃圾,然后使用环顾四周来匹配目标令牌之间的。
虽然有些正则表达式列车残骸,但这适用于任意“其他角色”,前提是单词用空格分隔,并且只能拔出目标令牌。例如,它适用于"xxx not yyy(zzz false aaa or bbb true ccc)ddd"
等输入。