Использование Keep-Left/ Right комбинатор не работает с конвертером результатов

У меня есть комбинатор и конвертер результатов, который выглядит так:

// 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 не важны для моего конвертера результатов, я надеялся, что смогу использовать <~ а также ~> в правильных местах в моем комбинаторе, так что мой конвертер не должен иметь с ними дело. В качестве эксперимента я изменил первый ~ в парсере к <~ и убрал ~ _ где "стрелка" будет соответствовать в case утверждение так:

private def subtitleHeader: Parser[SubtitleBlock] = {
  (subtitleNumber ~ whiteSpace).? ~>
    time <~ arrow ~ time ~ opt(textLine) ~ eol
} ^^ {
  case
    startTime ~ endTime ~ _ ~ _
  => SubtitleBlock(startTime, endTime, List(""))
}

Тем не менее, я получаю красные кривые в IntelliJ с сообщением об ошибке:

Ошибка:(44, 31) конструктор не может быть создан для ожидаемого типа; найдено: caption.vttdissector.VttParsers.~[a,b] обязательно: Int startTime ~ endTime ~ _ ~ _

Что я делаю неправильно?

1 ответ

Решение

Так как вы не вставили никаких скобок в цепочку ~ а также <~большинство подходящих подвыражений выбрасывается "с водой в ванне" (или, скорее, "с пробелами и стрелками"). Просто вставьте несколько скобок.

Вот общая схема, как она должна выглядеть:

(irrelevant ~> irrelevant ~> RELEVANT <~ irrelevant <~ irrelevant) ~
(irrelevant ~> RELEVANT <~ irrelevant <~ irrelevant) ~ 
...

т. е. каждое "соответствующее" подвыражение окружено несущественным материалом и парой скобок, а затем заключенные в скобки подвыражения связаны ~"S.

Ваш пример:

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()))
Другие вопросы по тегам