我正在编写一个文件解析器,它读取包含固定长度、0填充字符串的现有文件格式。
因此,例如,我在我需要解析的文件中有两个二进制结构的case类。第一个包含一个4个字符的字符串,可以是两个值中的一个,后者包括一个8个字符串(其中值长度小于8个字符是NUL填充的)。
case class WadHeader( magic : String, items : Int, dirOffset : Int)
case class LumpIndex( offset : Int, size : Int, lumpName : String)我尝试编写一个简单的编解码器来解析第一个代码:
implicit val headerCodec : Codec[WadHeader] = {
("magic" | bytes(4)) ::
("items" | uint32) ::
("dirOffset" | uint32)
}.as[WadHeader]但是,我发现它无法成功地将其转换为WadHeader (大概是因为神奇的值与案例类定义不完全匹配)。我希望能够摄取一个固定大小的字节字符串,并将其解码为string对象。
不幸的是,浏览文档只会出现“贪婪”字符串或大小前缀字符串选项。
发布于 2021-07-03 03:56:07
好的-所以我想出了一个可行的解决方案。也许有一种更简单、更干净的方法可以做到这一点,但效果很好。
首先,当我预先知道长度时,我定义了一个用于字符串读取的新的fixedString编解码器:
def fixedString(size: Int): Codec[String] = new Codec[String] {
private val codec = fixedSizeBytes(size, ascii)
def sizeBound: SizeBound = SizeBound.exact(size * 8L)
def encode(b: String): Attempt[BitVector] = codec.encode(b)
def decode(b: BitVector): Attempt[DecodeResult[String]] = {
codec.decode(b) match {
case Successful(DecodeResult(value, remainder)) =>
val decoded = value.toSeq.takeWhile(_>0).mkString
Attempt.successful(DecodeResult(decoded, remainder))
case fail : scodec.Attempt.Failure => fail
}
}
override def toString = s"fixedString($size)"
}这对绳子有用。第二个错误只是我自己犯的一个愚蠢的错误(uint32解码为一个长的,而不是Int),它要求我相应地更新我的案例类定义:
case class WadHeader( magic : String, items : Long, dirOffset : Long)
object WadHeader {
implicit val codec : Codec[WadHeader] = {
("magic" | fixedString(4)) ::
("items" | uint32) ::
("dirOffset" | uint32)
}.as[WadHeader]
}编辑: 5/7 -指出我可以包装fixedSizeCodec(size, ascii)而不是bytes,它完成了我想要的大部分工作,并相应地更新了解决方案。根据需求的不同,fixedSizeCodec(size, cstring)也可能是一个很好的解决方案--但是对于使用完整字段长度的字符串,我的用例失败了,因为没有终止nul的空间。
https://stackoverflow.com/questions/68225957
复制相似问题