title: How not to match a token within quote like “hello w"orld in javacc
body: <p>I'm doing a redis-cli parser by using javacc. I have to handle the quote</p>
  
  <p>for example <code>set "a b" "cd"</code>, I hope key token is <code>a b</code> and value token is <code>cd</code>.</p>
  
  <p>There is my solution:</p>
  
  <p>RedisCommand.java</p>
  
  <pre><code>package com.demo.command;
  public interface RedisCommand {
  }
  
  </code></pre>
  
  <p>SetCommand .java</p>
  
  <pre><code>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;
      }
  }
  
  </code></pre>
  
  <p>RedisCommand.jj</p>
  
  <pre><code>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 :
  {
    &lt;WHITESPACE: " " | "\t" | "\n" | "\r"&gt;
  }
  
  TOKEN :
  {
    &lt;K_SET: "set"&gt;
  }
  
  TOKEN :
  {
     &lt;SINGLE_QUOTE: "'"&gt;
     | &lt;DOUBLE_QUOTE: "\""&gt;
     | &lt;SINGLE_STRING: &lt;SINGLE_QUOTE&gt; ((~["'"]) | "\\'" )+ &lt;SINGLE_QUOTE&gt;&gt;
     | &lt;DOUBLE_STRING: &lt;DOUBLE_QUOTE&gt; ((~["\""]) | "\\\"" )+ &lt;DOUBLE_QUOTE&gt;&gt;
     | &lt;RAW_STRING: (~[" "])+&gt;
  }
  
  RedisCommand RedisCommand() :
  {
    RedisCommand command = null;
  }
  {
    command=SetCommand() &lt;EOF&gt;
    {
      return command;
    }
  }
  
  SetCommand SetCommand() :
  {
    SetCommand command = new SetCommand();
    String key = null;
    String value = null;
  }
  {
    &lt;K_SET&gt; key=StringParam() value=StringParam()
    {
      command.setKey(key);
      command.setValue(value);
      return command;
    }
  }
  
  String StringParam() :
  {
    String s = null;
    Token token = null;
    String im = null;
  }
  {
    (token=&lt;SINGLE_STRING&gt; { im=token.image; s=im.substring(1, im.length()-1);}
    | token=&lt;DOUBLE_STRING&gt; { im=token.image; s=im.substring(1, im.length()-1);}
    | s=RawString()
    )
    {return s;}
  }
  
  String RawString() :
  {}
  {
    /* for reserved word
     * support like 'set set set'
     */
    (&lt;K_SET&gt;
    | &lt;RAW_STRING&gt;
    )
    {
      return token.image;
    }
  }
  </code></pre>
  
  <p>SetCommandTest.java</p>
  
  <pre><code>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);
      }
  }
  
  </code></pre>
  
  <p>test4 in SetCommandTest failed, error message is </p>
  
  <pre><code>Call:   RedisCommand
    Call:   SetCommand
      Consumed token: &lt;"set" at line 1 column 1&gt;
      Call:   StringParam
        Consumed token: &lt;&lt;DOUBLE_STRING&gt;: ""ab c"" at line 1 column 5&gt;
      Return: StringParam
      Call:   StringParam
        Call:   RawString
          Consumed token: &lt;&lt;RAW_STRING&gt;: "d" at line 1 column 11&gt;
        Return: RawString
      Return: StringParam
    Return: SetCommand
    Consumed token: &lt;&lt;EOF&gt; at line 1 column 11&gt;
  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)
  </code></pre>
  
  <p>It take "ab c" as <code>&lt;DOUBLE_STRING&gt;</code>, which is not what I want. I think the problem is <code>&lt;DOUBLE_STRING&gt;</code>, quote after space and quote before space should work fine. Not all quote string is <code>&lt;DOUBLE_STRING&gt;</code>. but I don't know how to do. Please help me</p>