【问题标题】:Null value if matching group does not match/work如果匹配组不匹配/工作,则为空值
【发布时间】:2017-06-27 12:10:36
【问题描述】:

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

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

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
  }

【问题讨论】:

  • 你能发布你当前的正则表达式,它会匹配所有需要的值吗?
  • 如果您使用组,则在调用相关的Matcher#group 方法时,您应该能够让索引或命名组与返回null 的缺失部分匹配。这完全取决于您的实施。
  • 我现在正在尝试简化:您似乎想让connection_id: 在两种情况下都返回匹配项,对吧?因此,您只需要"""connection_id\s*:\s*(\d*)""" 并且将填充第 1 组 var。 \d* 匹配 0 个或多个数字,因此它将返回一个空字符串。
  • 查看后视版本示例 - ideone.com/csivBv。请出示您的代码。

标签: java regex scala logparser


【解决方案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
}

【讨论】:

    【解决方案2】:

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

    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"
    

    【讨论】:

    • 检查我的正则表达式,我使用了前瞻和后瞻。
    猜你喜欢
    • 2018-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-23
    • 2012-12-19
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多