如果匹配组没有 match/work,则为空值

Null value if matching group does not match/work

是否有 regex 表达式 return 为空值或如果未找到匹配项则为空值?

例如,我有处理此日志行的正则表达式:

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)

我的问题是我想处理此更改,我的想法是 return 如果 regex 找不到值,则为空值。我的下一步是构建配置单元 table,因此从 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

如果有任何帮助,我将不胜感激:)

2017 年 6 月 28 日更新

我的正则表达式: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
  }

因此,如果您要匹配一个不存在的可选组,您将获得该组的空值。我会像下面这样匹配,然后将潜在的 null 值包装在类型安全的选项中,然后从那里继续。

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"

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

您必须对此进行调整,因为您知道哪些部分是 variant/invariant,而我只有两个示例日志行可以使用。

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。不捕获任何内容的可选捕获组 return null 虽然 String 值可以是 null,但这不是好的做法。最好使用 Option[String] 代替。当我们这样做时,由于整个日志行可能无法通过模式识别,所以让我们也将 return 类型设为可选。

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
}