与Scala中的任意列表大小匹配

与Scala中的任意列表大小匹配,scala,pattern-matching,Scala,Pattern Matching,假设我有一个无限的物品清单。在这个列表中,我有时有一些东西指示隐藏消息即将开始,然后是消息长度、crc,然后是结束令牌。然后列表继续,在某个地方出现了一条新消息: a :: b :: start :: 3 :: 1 :: 2 :: 3 :: 4FAA :: end :: x :: y :: z :: .... 最惯用的模式(我想使用match)是什么 size = 3 payload = 1 :: 2 :: 3 crc = 4FAA 另外,考虑到令牌“start”可能出现在有效负载中,因此

假设我有一个无限的物品清单。在这个列表中,我有时有一些东西指示隐藏消息即将开始,然后是消息长度、crc,然后是结束令牌。然后列表继续,在某个地方出现了一条新消息:

a :: b :: start :: 3 :: 1 :: 2 :: 3 :: 4FAA :: end :: x :: y :: z :: .... 
最惯用的模式(我想使用
match
)是什么

size = 3
payload = 1 :: 2 :: 3
crc = 4FAA

另外,考虑到令牌“start”可能出现在有效负载中,因此必须依赖“完全匹配”。

您描述的语法是一种常规语言。最好使用
方法定义自定义,该方法可以将令牌列表解析为结构列表。

使用解析器组合器。对于您来说,确切的解决方案似乎是解析标记,但是,为了简化,我假设您正在读取由空格分隔的一串单词

object P extends scala.util.parsing.combinator.RegexParsers {
  def message: Parser[Any] = properMessage | dummy ~> message
  def properMessage = start ~> body <~ end
  def start = "(?i)start".r
  def end = "(?i)end".r
  def body = (size >> payload) ~ crc
  def crc = word
  def size = "\\d+".r ^^ (_.toInt)
  def payload = repN(_: Int, word)
  def word = "\\S+".r
  def dummy = word
}

现在,
RegexParsers
解析
Char
流。由于您有一个令牌流,
StandardTokenParsers
可能是一个更合适的类。或者您可以基于
解析器
,定义
元素
,以满足您的需要。

我认为有许多不同的方法可以解决这个问题。我首先想到的是以下递归解决方案:

def filterMessages(l:List[Any]):List[List[Any]] = {
    l match {
      case "start" :: tail => tail.takeWhile(_ != "end") :: filterMessages(tail.dropWhile(_ != "end"))
      case a :: tail => filterMessages(tail)
      case Nil  => Nil
    }
 }
这种方法将返回:

scala> val l = "a" :: "b" :: "start" :: 2 :: 1 :: 2:: "crc" :: "end" :: "a" :: "x"  ::  "start" :: 3 :: 1 :: 2 ::3 :: "crc" :: "end" :: "x" :: Nil
scala> println(filterMessages(l))
res0: List(List(2, 1, 2, crc), List(3, 1, 2, 3, crc))
如果你有一个“非常长”(无限)的列表,你应该让这个算法尾部递归。尾部递归解决方案如下所示(产生与上面相同的结果):

在处理方面,我将传入一个处理消息的函数,而不是将每个消息串联在一个列表中。此解决方案如下所示:

def processMessages(l: List[Any])(process: (List[Any]) => Unit): Unit = {
   l match {
      case "start" :: tail => process(tail.takeWhile(_ != "end")); processMessages(tail.dropWhile(_ != "end"))(process)
      case a :: tail => processMessages(tail)(process)
      case Nil => Nil
    }
}
用法:

scala> processMessages(l) { println }

这是一个非常有趣的建议,但我没有看到它将如何应用,实际上(…),因此您将使用方法
def unapply(List[Token]):Option[List[Foo]
定义一个
对象解析。然后,您使用模式匹配进行解析的界面如下所示:
tokens match{case Parse(foos)=>doSomething(foos)}
。。。或者您是在问更多关于如何实现实际解析的问题?
def processMessages(l: List[Any])(process: (List[Any]) => Unit): Unit = {
   l match {
      case "start" :: tail => process(tail.takeWhile(_ != "end")); processMessages(tail.dropWhile(_ != "end"))(process)
      case a :: tail => processMessages(tail)(process)
      case Nil => Nil
    }
}
scala> processMessages(l) { println }