Java 为什么这个简单的jparsec lexer失败了?

Java 为什么这个简单的jparsec lexer失败了?,java,parsing,tokenize,lexer,jparsec,Java,Parsing,Tokenize,Lexer,Jparsec,我将编写一个简单的lexer,它可以识别没有数字和数字的单词,而忽略空格 我使用jparsec v3.0编写了以下代码: final Parser words=Patterns.isChar(CharPredicates.IS_ALPHA).many1().toScanner(“word”).source(); 最终解析器nums=Patterns.isChar(CharPredicates.IS_DIGIT).many1().toScanner(“num”).source(); 最终解析器标记

我将编写一个简单的lexer,它可以识别没有数字和数字的单词,而忽略空格

我使用jparsec v3.0编写了以下代码:

final Parser words=Patterns.isChar(CharPredicates.IS_ALPHA).many1().toScanner(“word”).source();
最终解析器nums=Patterns.isChar(CharPredicates.IS_DIGIT).many1().toScanner(“num”).source();
最终解析器标记器=解析器。或(
words.map(it->Tokens.fragment(it,“WORD”)),
map(it->Tokens.fragment(it,“NUM”));
最终解析器lexer=tokenizer.lexer(Scanners.WHITESPACES);
但以下测试失败,出现异常
org.jparsec.error.ParserException:第1行第7列:预期EOF,遇到1个
。相反,使用字符串“abc cd 123”解析是成功的

final List get=lexer.parse(“abc cd123”);
预期最终列表=Arrays.asList(
新令牌(0,3,令牌.fragment(“abc”,“WORD”),
新令牌(4,2,令牌.片段(“cd”,“WORD”),
新标记(6,3,Tokens.fragment(“123”,“NUM”));
assertEquals(预期、获得);

您认为有什么问题?

以下测试通过:

public class SOTest {
  final Parser<String> words = Patterns.isChar(CharPredicates.IS_ALPHA).many1().toScanner("word").source();
  final Parser<String> nums = Patterns.isChar(CharPredicates.IS_DIGIT).many1().toScanner("num").source();
  final Parser<Tokens.Fragment> tokenizer = Parsers.or(
    words.map(it -> Tokens.fragment(it, "WORD")),
    nums.map(it -> Tokens.fragment(it, "NUM")));
  final Parser<List<Token>> lexer = tokenizer.lexer(Scanners.WHITESPACES);


  @Test public void test(){
    final List<Token> got = lexer.parse("abc cd 123");
    Asserts.assertArrayEquals(got.toArray(new Token[0]),
      new Token(0, 3, Tokens.fragment("abc", "WORD")),
      new Token(4, 2, Tokens.fragment("cd", "WORD")),
      new Token(7, 3, Tokens.fragment("123", "NUM")));
  }      
}
公共类SOTest{
最终解析器words=Patterns.isChar(CharPredicates.IS_ALPHA).many1().toScanner(“word”).source();
最终解析器nums=Patterns.isChar(CharPredicates.IS_DIGIT).many1().toScanner(“num”).source();
最终解析器标记器=解析器。或(
words.map(it->Tokens.fragment(it,“WORD”)),
map(it->Tokens.fragment(it,“NUM”));
最终解析器lexer=tokenizer.lexer(Scanners.WHITESPACES);
@测试公共无效测试(){
最终列表get=lexer.parse(“abc cd 123”);
Asserts.assertArrayEquals(got.toArray(新令牌[0]),
新令牌(0,3,令牌.fragment(“abc”,“WORD”),
新令牌(4,2,令牌.片段(“cd”,“WORD”),
新标记(7,3,Tokens.fragment(“123”,“NUM”));
}      
}
您的令牌要么只是
ALPHA
字符,要么只是
数字
,因此无法解析
abc cd123
是正常的


文档中说“在每次出现之前或之后忽略分隔符”这一事实应该解释为:在解析的
标记
列表之前或之后出现的分隔符被忽略。但是分隔符不会被忽略以分隔令牌,除非操作员(有关更多信息,请参见
终端
类)的情况除外。

只需将分隔符设置为可选,即可解决此问题:

tokenizer.lexer(Scanners.WHITESPACES.optional(null))

既然您是基于空格进行词法分析,那么与您的令牌列表等价的不是
“abc cd 123”
?根据文档,
Parser.lexer(…)
应该反复运行解析器(
tokenizer
),忽略delimeter(
空格
)识别的模式每次发生前后。不清楚分隔符是否是可选的,因此我希望生成的lexer匹配“abc”,然后忽略空格,然后匹配“cd”,最后匹配“123”。感谢您的澄清。所以我误解了Parser.lexer方法,它不应该以这种方式使用。但最后,如何实现一个lexer,它接受“abccd123”和“abccd123”,生成相同的令牌序列(除了偏移量)?