我们有一个文件,其中包含我们想要与案例类匹配的数据。我知道足够的知识来暴力破解它,但在 scala 中寻找一种惯用的方法。
给定文件:
#record
name:John Doe
age: 34
#record
name: Smith Holy
age: 33
# some comment
#record
# another comment
name: Martin Fowler
age: 99
(两行字段值无效,例如 name:John\n Smith 应该出错)
以及案例类
case class Record(name:String, age:Int)
我想返回一个Seq类型,例如Stream:
val records: Stream records
我正在研究但到目前为止尚未实现的几个想法是:
删除所有新行并将整个文件视为一个长字符串。然后 grep match 字符串 "((?!name).)+((?!age).)+age:([\s\d]+)"并为每个匹配创建我的案例类的一个新对象,但是到目前为止,我的正则表达式 foo 很低,无法匹配注释。
递归思想:遍历每一行找到第一条匹配record的行,然后递归调用函数匹配name,然后是age。当命中下一个
记录
时,Tail 递归返回Some(new Record(cumulativeMap.get(name),cumulativeMap.get(age))
或None
在name
之后(即从未遇到过age
)??更好的主意?
感谢您的阅读!该文件比上面更复杂,但所有规则都是相同的。出于好奇:我正在尝试解析自定义 M3U 播放列表文件格式。
最佳答案
我会使用kantan.regex一个相当简单的基于正则表达式的解决方案。
无需花哨的无定形推导,您可以编写以下内容:
import kantan.regex._
import kantan.regex.implicits._
case class Record(name:String, age:Int)
implicit val decoder = MatchDecoder.ordered(Record.apply _)
input.evalRegex[Record](rx"(?:name:\s*([^\n]+))\n(?:age:\s*([0-9]+))").toList
这会产生:
List(Success(Record(John Doe,34)), Success(Record(Smith Holy,33)), Success(Record(Martin Fowler,99)))
请注意,此解决方案需要您手动编写解码器
,但它通常可以自动派生。如果你不介意无形的依赖,你可以简单地写:
import kantan.regex._
import kantan.regex.implicits._
import kantan.regex.generic._
case class Record(name:String, age:Int)
input.evalRegex[Record](rx"(?:name:\s*([^\n]+))\n(?:age:\s*([0-9]+))").toList
并得到完全相同的结果。
免责声明:我是该库的作者。
关于regex - 在 Scala 中将文件中的字符串与案例类匹配的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40539743/