我正在处理一个日志文件,以使用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)
以某种方式,我以回旋处/冗余的方式进行操作。是否有更好的方法来完成此操作?
答案 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)