如果匹配组不匹配/工作,则为空值

时间:2017-06-27 12:10:37

标签: java regex scala logparser

如果找不到匹配,是否有任何regex表达式返回空值或空值?

例如,我有正则表达式来处理这个日志行:

May  5 23:00:01 99.99.99.99 %FRA-8-333344: Built inbound UDP connection 9999888811 for outside:11.111.111.11/47747 (11.111.111.11/47747) to net-9999:22.22.22.22/53 (22.22.22.22/53)

但有时日志不同,例如缺少一个值(例如:缺少连接ID):

May  5 23:00:01 99.99.99.99 %FRA-8-333344: Built inbound UDP for outside:11.111.111.11/47747 (11.111.111.11/47747) to net-9999:22.22.22.22/53 (22.22.22.22/53)

我的问题是我想要处理这个更改,我的想法是在regex找不到值时返回空值。我的下一步是构建hive表,因此regex中的值提取必须具有正确的顺序,例如UDP值不能写在连接id列上。

有谁知道这个问题的解决方案?在R语言中,解决方案非常简单(str_extract_all)和正则表达式数组,但在Scala中我无法处理..

第一个日志中的

键值:

timestamp: May  5 23:00:01
Action: Built
protocol: UDP
connection_id: 9999888811
src_ip: 11.111.111.11
dst_ip:  22.22.22.22
src_port  47747
dst_port 53
第二个日志中的

键值:

timestamp: May  5 23:00:01
Action: Built
protocol: UDP
connection_id: **EMPTY/NULL/" "**
src_ip: 11.111.111.11
dst_ip:  22.22.22.22
src_port  47747
dst_port 53

对于每一个帮助,我将不胜感激:)

更新28.06.2017

我的正则表达式:https://regex101.com/r/4mtAtu/1

我的解决方案。我认为这会很慢:

case class logValues(time_stamp: String, action: String, protocol: String, connection_id: String, ips: String, ports: String)


def matchLog(x: String): logValues = {

  val time_stamp =  """^.*?(?=\s\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\s%)""".r.findAllIn(x).mkString(",")
    val action = """((?<=:\s)\w{4,10}(?=\s\w{2})|(?<=\w\s)(\w{7,9})(?=\s[f]))""".r.findAllIn(x).mkString(",")
    val protocol = """(?<=[\w:]\s)(\w+)(?=\s[cr])""".r.findAllIn(x).mkString(",")
    val connection_id = """(?<=\w\s)(\d+)(?=\sfor)""".r.findAllIn(x).mkString(",")
    val ips = """(?<=[\d\w][:\s])(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?=\/\d+|\z| \w)""".r.findAllIn(x).mkString("|")
    val ports = """(?<=\d/)(\d{1,6})(?=\z|[\s(])""".r.findAllIn(x).mkString("|")

    val logObject = logValues(time_stamp, action, protocol, connection_id, ips, ports)

    return logObject
  }

2 个答案:

答案 0 :(得分:1)

您正在编译六种不同的正则表达式模式,然后将输入字符串提交给六种不同的测试。另一种方法是为整个日志行创建单个正则表达式,并通过捕获组提取所需的信息。

您必须调整此项,因为您知道哪些部分是变体/不变的,我只有两个示例日志行可供使用。

val logPattern =
  raw"^(.*)\s"                                    + // timestamp
  raw"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\s%\S+\s" +
  raw"(\w+)?\s\w+\s"                              + // action
  raw"(\w+)?\s\w*\s*"                             + // protocol
  raw"(\d+)?\s.*outside:"                         + // connection ID
  raw"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/"      + // src IP
  raw"(\d+).*:"                                   + // src port
  raw"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/"      + // dst IP
  raw"(\d+)"                                        // dst port

val logRE = logPattern.r.unanchored  // only once

好处:效率更高,一切都在一个地方。缺点:如果一个部分不正确,整个模式可能会失败。 (注意:只编译一次正则表达式模式。不是每次都传入新的日志行。)

现在提取更直接。

log_line match {
  case logRE(ts,act,ptcl,cid,sip,sprt,dip,dprt) =>
    LogValues(ts,act,ptcl,cid,s"$sip/$dip",s"$sprt/$dprt")
  case _ => /* log line doesn't fit pattern */
}

您注意我已将三个字段设为可选:actionprotocolconnection ID。不能捕获任何内容的可选捕获组会返回null,虽然String值为null,但它不被视为良好做法。更好的是使用Option[String]代替。虽然我们对此感兴趣,但由于整个日志行可能无法通过模式识别,因此我们也可以选择返回类型。

case class LogValues( time_stamp    : String
                    , action        : Option[String]
                    , protocol      : Option[String]
                    , connection_id : Option[String]
                    , ips           : String
                    , ports         : String
                    )

log_Line match {
  case logRE(ts,act,ptcl,cid,sip,sprt,dip,dprt) =>
    Some(LogValues( ts
                  , Option(act)
                  , Option(ptcl)
                  , Option(cid)
                  , s"$sip/$dip"
                  , s"$sprt/$dprt" ))
  case _ => /* log line doesn't fit pattern */
    None
}

答案 1 :(得分:0)

因此,如果您匹配的是一个不存在的可选组,那么您将获得该组的空值。我将匹配如下所示,然后在类型安全的选项中包含可能为空的值,并从那里继续。

mshelton-mshelton@ val sampleRegex = """(\w+)-(\w+)?-(\w+)""".r
sampleRegex: scala.util.matching.Regex = (\w+)-(\w+)?-(\w+)
mshelton-mshelton@ val sampleRegex(a, b, c) = "aaa-bbb-ccc"
a: String = "aaa"
b: String = "bbb"
c: String = "ccc"
mshelton-mshelton@ val sampleRegex(a, b, c) = "aaa--ccc"
a: String = "aaa"
b: String = null
c: String = "ccc"