2017-01-08 12 views
1

숫자 을 인식하는 간단한 렉서를 쓰고 숫자는이고 공백은 무시합니다.이 간단한 jparsec 렉서가 실패하는 이유는 무엇입니까?

나는 jparsec 버전 3.0을 사용하여 다음 코드를 작성 :

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); 

그러나 다음 테스트는 예외 org.jparsec.error.ParserException: line 1, column 7: EOF expected, 1 encountered와 함께 실패합니다. 대신 문자열 "abc cd 123"을 사용하면 구문 분석이 성공적입니다.

final List<Token> got = lexer.parse("abc cd123"); 
final List<Token> expected = Arrays.asList(
     new Token(0, 3, Tokens.fragment("abc", "WORD")), 
     new Token(4, 2, Tokens.fragment("cd", "WORD")), 
     new Token(6, 3, Tokens.fragment("123", "NUM"))); 
assertEquals(expected, got); 

무엇이 잘못 되었습니까?

+0

는 토큰 목록에 상응하지 않을까요' "ABC의 CD 123"'당신은 공백에 따라 렉싱 것 때문에? – Aurora0001

+0

문서에 따르면'Parser.lexer (...)'는 구문 분석기 ('tokenizer')를 반복적으로 실행하여 각 문자의 앞뒤에 delimeter ('WHITESPACES')가 인식하는 패턴을 무시해야합니다. 구분 기호가 선택적인지 여부는 명확하지 않으므로 결과로 나오는 렉서가 "abc"와 일치하고 공백을 무시한 다음 "cd"와 마침내 "123"을 찾습니다. – maurocchi

답변

0

문제는 구분 기호를 선택함으로써 간단히 해결되었습니다

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

다음 시험 통과 : 당신이 abc cd123을 구문 분석 할 수 없습니다

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"))); 
    }  
} 

토큰은 어느에만 ALPHA 문자 또는 단지 DIGITS이다, 따라서 그것은 정상입니다.

이 문서는 "구분 기호가 전에 각 선두로부터 후 무시됩니다"라는 사실은 전이나 무시됩니다 분석 Token의의 목록 뒤에 나타나는 구분자 의미로 해석되어야한다. 그러나 구획 문자는 토큰을 분리하기 위해 무시되지 않습니다 (연산자에 대한 자세한 내용은 Terminals 클래스 참조).

+0

설명해 주셔서 감사합니다. 그래서 나는'Parser.lexer' 메쏘드를 오해했고 이런 식으로 사용해서는 안됩니다. 그러나 마지막으로 "abc cd123"및 "abc cd 123"을 허용하는 렉서를 구현하여 동일한 순서의 토큰을 생성하는 방법 (오프셋 제외)은 무엇입니까? – maurocchi