Я делаю парсер redis-cli с помощью javacc. Я должен справиться с цитатой
например set "a b" "cd"
, я надеюсь, что ключевой токен a b
и значение токена cd
.
Вот мое решение:
RedisCommand.java
package com.demo.command;
public interface RedisCommand {
}
SetCommand .java
package com.demo.command;
public class SetCommand implements RedisCommand{
private String key;
private String value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
RedisCommand.jj
options {
STATIC = false;
DEBUG_PARSER=true;
}
PARSER_BEGIN(RedisCommandParser)
package com.demo.parser;
import com.demo.command.*;
import java.util.*;
public class RedisCommandParser {
public static void main(String args[]) throws ParseException {
RedisCommandParser parser = new RedisCommandParser(System.in);
parser.RedisCommand();
}
}
PARSER_END(RedisCommandParser)
SKIP :
{
<WHITESPACE: " " | "\t" | "\n" | "\r">
}
TOKEN :
{
<K_SET: "set">
}
TOKEN :
{
<SINGLE_QUOTE: "'">
| <DOUBLE_QUOTE: "\"">
| <SINGLE_STRING: <SINGLE_QUOTE> ((~["'"]) | "\\'" )+ <SINGLE_QUOTE>>
| <DOUBLE_STRING: <DOUBLE_QUOTE> ((~["\""]) | "\\\"" )+ <DOUBLE_QUOTE>>
| <RAW_STRING: (~[" "])+>
}
RedisCommand RedisCommand() :
{
RedisCommand command = null;
}
{
command=SetCommand() <EOF>
{
return command;
}
}
SetCommand SetCommand() :
{
SetCommand command = new SetCommand();
String key = null;
String value = null;
}
{
<K_SET> key=StringParam() value=StringParam()
{
command.setKey(key);
command.setValue(value);
return command;
}
}
String StringParam() :
{
String s = null;
Token token = null;
String im = null;
}
{
(token=<SINGLE_STRING> { im=token.image; s=im.substring(1, im.length()-1);}
| token=<DOUBLE_STRING> { im=token.image; s=im.substring(1, im.length()-1);}
| s=RawString()
)
{return s;}
}
String RawString() :
{}
{
/* for reserved word
* support like 'set set set'
*/
(<K_SET>
| <RAW_STRING>
)
{
return token.image;
}
}
SetCommandTest.java
package com.demo.command;
import com.demo.parser.ParseException;
import com.demo.parser.RedisCommandParser;
import org.junit.Test;
import java.io.StringReader;
public class SetCommandTest {
@Test
public void test() throws ParseException {
//test1
_test("set a b", "a", "b");
//test2
_test("set \"a b\" cd", "a b", "cd");
//test3
_test("set a\"b c\"d", "a\"b", "c\"d");
//test4
_test("set \"ab c\"d", "\"ab", "c\"d");
}
private void _test(String line, String expectKey, String expectValue) throws ParseException {
RedisCommandParser parser = new RedisCommandParser(new StringReader(line));
SetCommand command = (SetCommand) parser.RedisCommand();
String key = command.getKey();
assert key.equals(expectKey) : String.format("command[%s] key[%s] expect[%s]", line, key, expectKey);
String value = command.getValue();
assert value.equals(expectValue) : String.format("command[%s] value[%s] expect[%s]", line, value, expectValue);
}
}
test4 в SetCommandTest завершился неудачно, сообщение об ошибке
Call: RedisCommand
Call: SetCommand
Consumed token: <"set" at line 1 column 1>
Call: StringParam
Consumed token: <<DOUBLE_STRING>: ""ab c"" at line 1 column 5>
Return: StringParam
Call: StringParam
Call: RawString
Consumed token: <<RAW_STRING>: "d" at line 1 column 11>
Return: RawString
Return: StringParam
Return: SetCommand
Consumed token: <<EOF> at line 1 column 11>
Return: RedisCommand
java.lang.AssertionError: command[set "ab c"d] key[ab c] expect["ab]
at com.demo.command.SetCommandTest._test(SetCommandTest.java:33)
at com.demo.command.SetCommandTest.test(SetCommandTest.java:26)
Он принимает "ab c" как <DOUBLE_STRING>
, а это не то, что я хочу. Я думаю, что проблема в <DOUBLE_STRING>
, кавычки после пробела и кавычки до пробела должны работать нормально. Не вся строка кавычки <DOUBLE_STRING>
. но я не знаю как это сделать. Пожалуйста, помогите мне