Scala使用简化的正则表达式获取读取,写入和拒绝记录

时间:2018-11-22 13:27:59

标签: scala scala-collections

我正在处理一个日志文件,以使用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)

以某种方式,我以回旋处/冗余的方式进行操作。是否有更好的方法来完成此操作?

3 个答案:

答案 0 :(得分:2)

鉴于读/写/拒绝文本的相似性,您可以将多个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 :(得分:1)

对我很好。仅需改进的三件事:

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]可以通过简单的Map转换为toMap

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

答案 2 :(得分:1)

如果您愿意将日志的措辞用于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)