2012-11-13 2 views
12

줄 바꿈 문자로 구분 된 단어 목록을 읽는 스칼라 파서 연결자 문법을 작성 중입니다. 목록은 하나 이상의 빈 줄로 구분됩니다. 다음과 같은 문자열이 주어진다 :스칼라 파서 연결자와 줄 바꿈 텍스트

cat 
mouse 
horse 

apple 
orange 
pear 

나는 그것을 List(List(cat, mouse, horse), List(apple, orange, pear))으로 돌려 보내고 싶다.

단어 목록을 줄 바꿈 문자로 처리하는 기본 문법을 작성했습니다. 기본 정의 인 whitespace을 재정의해야합니다. 이

[8.1] parsed: List(List(cat, mouse, horse), List(), List(apple, orange, pear)) 

반환, 즉

import util.parsing.combinator.RegexParsers 

object WordList extends RegexParsers { 

    private val eol = sys.props("line.separator") 

    override val whiteSpace = """[ \t]+""".r 

    val list: Parser[List[String]] = repsep("""\w+""".r, eol) 

    val lists: Parser[List[List[String]]] = repsep(list, eol) 

    def main(args: Array[String]) { 
     val s = 
      """cat 
      |mouse 
      |horse 
      | 
      |apple 
      |orange 
      |pear""".stripMargin 

     println(parseAll(lists, s)) 
    } 
} 

이 잘못 빈 단어 목록으로 빈 줄을 처리합니다 (중간에 빈리스트를 참고.)

전에서 라인의 선택에 종지부를 찍을 수 있습니다 각 목록의 끝.

val list: Parser[List[String]] = repsep("""\w+""".r, eol) <~ opt(eol) 

목록 사이에 빈 줄 하나가있는 경우를 처리하지만 여러 빈 줄과 동일한 문제가있는 경우를 처리합니다.

val lists:Parser[List[List[String]]] = repsep(list, rep(eol)) 

을하지만, 이것은 상기 입력에 응답 :

I 여러 줄 끝 분리를 허용하도록 lists 정의를 변경했습니다.

구분 기호로 여러 공백 행을 처리하는 올바른 문법은 무엇입니까?

답변

13

공백 정의를 재정의하는 대신 skipWhitespace에서 false으로 설정해야합니다. 빈 목록에있는 문제는 repsep이 목록 끝에 줄 바꿈을 사용하지 않는다는 사실 때문에 발생합니다. 각 항목 후 대신 줄 바꿈을 분석한다 (또는 아마도 입력의 끝) :

import util.parsing.combinator.RegexParsers 

object WordList extends RegexParsers { 

    private val eoi = """\z""".r // end of input 
    private val eol = sys.props("line.separator") 
    private val separator = eoi | eol 
    private val word = """\w+""".r 

    override val skipWhitespace = false 

    val list: Parser[List[String]] = rep(word <~ separator) 

    val lists: Parser[List[List[String]]] = repsep(list, rep1(eol)) 

    def main(args: Array[String]) { 
    val s = 
     """cat 
     |mouse 
     |horse 
     | 
     |apple 
     |orange 
     |pear""".stripMargin 

    println(parseAll(lists, s)) 
    } 

} 

그럼 다시, 파서 콤비가 과잉 여기에 조금 있습니다.

s.split("\n{2,}").map(_.split("\n")) 
+0

단어 목록 사이에 빈 줄이 하나만있는 경우 작동합니다. 목록 대신 공백이 하나만 있으면 작동합니다. _n_ 빈 줄이 있으면 중간에 _n-1_ 가짜 빈 목록이 생깁니다. (BTW :'skipWhitespace'와'eoi' 예제는 매우 도움이됩니다.) –

+0

@ W.P.McNeill - 문자열 목록 사이에서'rep1 (eol)'을 찾도록 코드를 업데이트했습니다. 그게 네가 가고 있었던거야? – DaoWen

+1

'rep1 (eol)'이 내가 찾고 있던 것이다. 감사. 나는 파서 결합 자들이 과잉이라고 여기 있습니다. 나는 설명의 목적으로 의도적으로 문제를 단순화했다. –