使用 keep-left/right 组合器不适用于结果转换器
Using keep-left/right combinator is not working with result converter
我有一个组合器和一个结果转换器,如下所示:
// parses a line like so:
//
// 2
// 00:00:01.610 --> 00:00:02.620 align:start position:0%
//
private def subtitleHeader: Parser[SubtitleBlock] = {
(subtitleNumber ~ whiteSpace).? ~>
time ~ arrow ~ time ~ opt(textLine) ~ eol
} ^^ {
case
startTime ~ _ ~ endTime ~ _ ~ _
=> SubtitleBlock(startTime, endTime, List(""))
}
因为 arrow
、textline
和 eol
对我的结果转换器不重要,我希望我可以使用 <~
和 ~>
我的组合器中的正确位置,这样我的转换器就不必处理它们。作为实验,我将解析器中的第一个 ~
更改为 <~ 并删除了 ~ _
,其中 "arrow" 将在 case
语句中匹配,如下所示:
private def subtitleHeader: Parser[SubtitleBlock] = {
(subtitleNumber ~ whiteSpace).? ~>
time <~ arrow ~ time ~ opt(textLine) ~ eol
} ^^ {
case
startTime ~ endTime ~ _ ~ _
=> SubtitleBlock(startTime, endTime, List(""))
}
但是,我在 IntelliJ 中出现红色波浪线和错误消息:
Error:(44, 31) constructor cannot be instantiated to expected type;
found : caption.vttdissector.VttParsers.~[a,b] required: Int
startTime ~ endTime ~ _ ~ _
我做错了什么?
因为您没有在 ~
和 <~
的链中插入任何括号,所以大多数匹配的子表达式都会被丢弃 "with the bathwater"(或者 "with the whitespace and arrows")。只需插入一些括号。
这是一般模式,它应该是这样的:
(irrelevant ~> irrelevant ~> RELEVANT <~ irrelevant <~ irrelevant) ~
(irrelevant ~> RELEVANT <~ irrelevant <~ irrelevant) ~
...
即每个 "relevant" 子表达式都被不相关的东西和一对括号包围,然后括号内的子表达式由 ~
连接。
你的例子:
import scala.util.parsing.combinator._
import scala.util.{Either, Left, Right}
case class SubtitleBlock(startTime: String, endTime: String, text: List[String])
object YourParser extends RegexParsers {
def subtitleHeader: Parser[SubtitleBlock] = {
(subtitleNumber.? ~> time <~ arrow) ~
time ~
(opt(textLine) <~ eol)
} ^^ {
case startTime ~ endTime ~ _ => SubtitleBlock(startTime, endTime, Nil)
}
override val whiteSpace = "[ \t]+".r
def arrow: Parser[String] = "-->".r
def subtitleNumber: Parser[String] = "\d+".r
def time: Parser[String] = "\d{2}:\d{2}:\d{2}.\d{3}".r
def textLine: Parser[String] = ".*".r
def eol: Parser[String] = "\n".r
def parseStuff(s: String): scala.util.Either[String, SubtitleBlock] =
parseAll(subtitleHeader, s) match {
case Success(t, _) => scala.util.Right(t)
case f => scala.util.Left(f.toString)
}
def main(args: Array[String]): Unit = {
val examples: List[String] = List(
"2 00:00:01.610 --> 00:00:02.620 align:start position:0%\n"
) ++ args.map(_ + "\n")
for (x <- examples) {
println(parseStuff(x))
}
}
}
发现:
Right(SubtitleBlock(00:00:01.610,00:00:02.620,List()))
我有一个组合器和一个结果转换器,如下所示:
// parses a line like so:
//
// 2
// 00:00:01.610 --> 00:00:02.620 align:start position:0%
//
private def subtitleHeader: Parser[SubtitleBlock] = {
(subtitleNumber ~ whiteSpace).? ~>
time ~ arrow ~ time ~ opt(textLine) ~ eol
} ^^ {
case
startTime ~ _ ~ endTime ~ _ ~ _
=> SubtitleBlock(startTime, endTime, List(""))
}
因为 arrow
、textline
和 eol
对我的结果转换器不重要,我希望我可以使用 <~
和 ~>
我的组合器中的正确位置,这样我的转换器就不必处理它们。作为实验,我将解析器中的第一个 ~
更改为 <~ 并删除了 ~ _
,其中 "arrow" 将在 case
语句中匹配,如下所示:
private def subtitleHeader: Parser[SubtitleBlock] = {
(subtitleNumber ~ whiteSpace).? ~>
time <~ arrow ~ time ~ opt(textLine) ~ eol
} ^^ {
case
startTime ~ endTime ~ _ ~ _
=> SubtitleBlock(startTime, endTime, List(""))
}
但是,我在 IntelliJ 中出现红色波浪线和错误消息:
Error:(44, 31) constructor cannot be instantiated to expected type; found : caption.vttdissector.VttParsers.~[a,b] required: Int startTime ~ endTime ~ _ ~ _
我做错了什么?
因为您没有在 ~
和 <~
的链中插入任何括号,所以大多数匹配的子表达式都会被丢弃 "with the bathwater"(或者 "with the whitespace and arrows")。只需插入一些括号。
这是一般模式,它应该是这样的:
(irrelevant ~> irrelevant ~> RELEVANT <~ irrelevant <~ irrelevant) ~
(irrelevant ~> RELEVANT <~ irrelevant <~ irrelevant) ~
...
即每个 "relevant" 子表达式都被不相关的东西和一对括号包围,然后括号内的子表达式由 ~
连接。
你的例子:
import scala.util.parsing.combinator._
import scala.util.{Either, Left, Right}
case class SubtitleBlock(startTime: String, endTime: String, text: List[String])
object YourParser extends RegexParsers {
def subtitleHeader: Parser[SubtitleBlock] = {
(subtitleNumber.? ~> time <~ arrow) ~
time ~
(opt(textLine) <~ eol)
} ^^ {
case startTime ~ endTime ~ _ => SubtitleBlock(startTime, endTime, Nil)
}
override val whiteSpace = "[ \t]+".r
def arrow: Parser[String] = "-->".r
def subtitleNumber: Parser[String] = "\d+".r
def time: Parser[String] = "\d{2}:\d{2}:\d{2}.\d{3}".r
def textLine: Parser[String] = ".*".r
def eol: Parser[String] = "\n".r
def parseStuff(s: String): scala.util.Either[String, SubtitleBlock] =
parseAll(subtitleHeader, s) match {
case Success(t, _) => scala.util.Right(t)
case f => scala.util.Left(f.toString)
}
def main(args: Array[String]): Unit = {
val examples: List[String] = List(
"2 00:00:01.610 --> 00:00:02.620 align:start position:0%\n"
) ++ args.map(_ + "\n")
for (x <- examples) {
println(parseStuff(x))
}
}
}
发现:
Right(SubtitleBlock(00:00:01.610,00:00:02.620,List()))