我正在编写一个Scala解析器组合语法,它读取换行符分隔的单词列表,其中列表由一个或多个空行分隔。给出以下字符串:
cat
mouse
horse
apple
orange
pear
我想让它返回List(List(cat, mouse, horse), List(apple, orange, pear))
。
我写了这个基本语法,将单词列表视为换行符分隔的单词。请注意,我必须覆盖whitespace
的默认定义。
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))
}
}
这会错误地将空白行视为空单词列表,即返回
[8.1] parsed: List(List(cat, mouse, horse), List(), List(apple, orange, pear))
(注意中间的空列表。)
我可以在每个列表的末尾添加一个可选的行尾。
val list: Parser[List[String]] = repsep( """\w+""".r, eol) <~ opt(eol)
这可以处理列表之间只有一个空行的情况,但是多个空白行有同样的问题。
我尝试更改lists
定义以允许多个行尾分隔符:
val lists:Parser[List[List[String]]] = repsep(list, rep(eol))
但这取决于上面的输入。
将多个空白行作为分隔符处理的正确语法是什么?
答案 0 :(得分: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))
}
}
然后,解析器组合器在这里有点矫枉过正。你可以得到几乎相同的东西(但是使用Arrays而不是Lists),这些东西更简单:
s.split("\n{2,}").map(_.split("\n"))