如果找不到匹配,是否有任何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
}
答案 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 */
}
您注意我已将三个字段设为可选:action
,protocol
和connection 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"