scala通过简化的regex获取读取、写入和拒绝记录



我正在处理一个日志文件,使用scala解析读取/写入/拒绝的记录,并将它们转换为Map。值出现在不同的行中——"读取",然后在下一行中"写入",然后"拒绝"。。

我使用的代码片段是

val log_text =
"""
|server.net|Wed Apr  8 05:44:24 2018|acct_reformat.000||finish|
|            120 records (              7200 bytes) read
|            100 records (              6000 bytes) written
|             20 records (              1200 bytes) rejected|
|server.net|Wed Apr  8 05:44:24 2018|acct_reformat_rfm_logs
""".stripMargin
val read_pat = """(d+) (records) (.*)""".r
val write_pat = """(?s)records .*? (d+) (records)(.*)""".r
val reject_pat = """(?s).* (d+) (records)""".r
val read_recs  = read_pat.findAllIn(log_text).matchData.map( m=> m.subgroups(0) ).take(1).mkString
val write_recs = write_pat.findAllIn(log_text).matchData.map( m=> m.subgroups(0) ).take(1).mkString
val reject_recs = reject_pat.findAllIn(log_text).matchData.map( m=> m.subgroups(0) ).take(1).mkString
val log_summ = List("Read",read_recs,"Write",write_recs,"Reject",reject_recs).sliding(2,2).map( p => p match { case List(x,y) => (x,y)}).toMap

导致

log_summ: scala.collection.immutable.Map[String,String] = Map(Read -> 120, Write -> 100, Reject -> 20)

不知怎么的,我觉得我在拐弯抹角地做这件事。。有更好的方法来实现这一点吗?。

考虑到读/写/拒绝文本的相似性,您可以将多个Regex匹配模式简化为通用模式,并使用zip生成Map,如下所示:

val pattern = """(d+) records .*""".r
val keys = List("Read", "Write", "Reject")
val values = pattern.findAllIn(log_text).matchData.map(_.subgroups(0)).toList
// values: List[String] = List(120, 100, 20)
val log_summ = (keys zip values).toMap
// log_summ: scala.collection.immutable.Map[String,String] =
//   Map(Read -> 120, Write -> 100, Reject -> 20)

我觉得不错。只有三件事需要改进:

1(IntelliJ是你的朋友。它会立即给你两个意图:

  • m.subgroups(0)->m.subgroups.head
  • map(p => p match { case List(x, y) => (x, y) })->map { case List(x, y) => (x, y) }

2(干燥。不要重复读/写/拒绝相关代码三次。只要把它放在某个地方一次。例如:

case class Processor(name: String, patternString: String) {
lazy val pattern: Regex = patternString.r
}
val processors = Seq(
Processor("Read", """(d+) (records) (.*)"""),
Processor("Write", """(?s)records .*? (d+) (records)(.*)"""),
Processor("Reject", """(?s).* (d+) (records)"""),
)
def read_recs(processor: Processor) = processor.pattern.findAllIn(log_text).matchData.map(m => m.subgroups.head).take(1).mkString

3(List[Tuple2]可以通过简单的toMap转换为Map

val log_summ = processors.map(processor => processor.name -> read_recs(processor)).toMap

如果您愿意使用Map键的日志措辞,可以在一次过程中完成。

val Pattern = raw"(d+) records .*) ([^|]+)".r.unanchored
log_text.split("n").flatMap{
case Pattern(num, typ) => Some(typ -> num)
case _ => None
}.toMap
//res0: immutable.Map[String,String] = Map(read -> 120, written -> 100, rejected -> 20)

最新更新