Scala получает чтение, запись и отклонение записей с упрощенным регулярным выражением - PullRequest
0 голосов
/ 22 ноября 2018

Я работаю над файлом журнала, чтобы проанализировать прочитанные / записанные / отклоненные записи, используя scala, и преобразовать их в карту.Значения присутствуют в разных строках - «чтение», затем «запись» в следующей строке, а затем «отклонение» ..

Фрагмент кода, который я использую:

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 голосов
/ 22 ноября 2018

Учитывая сходство текста для чтения / записи / отклонения, вы можете упростить несколько шаблонов сопоставления 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)
0 голосов
/ 22 ноября 2018

Это можно сделать за один проход, если вы хотите использовать формулировку журнала для клавиш 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)
0 голосов
/ 22 ноября 2018

выглядит хорошо для меня.Всего три вещи для улучшения:

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
...