Parsing 从字符串中的子字符串转到分析日期
我正在编写一个日志文件解析器,并且已经编写了一些测试代码来用C解析它 要分析的字符串如下所示:Parsing 从字符串中的子字符串转到分析日期,parsing,time,go,Parsing,Time,Go,我正在编写一个日志文件解析器,并且已经编写了一些测试代码来用C解析它 要分析的字符串如下所示: s := `10.0.0.1 Jan 11 2014 10:00:00 hello` 在C语言中,就地解析是相当容易的。首先,我在字符串中找到指向日期的指针,然后使用strtime()尽可能多地使用它。这是可能的,因为调用后strptime()将返回字符串中的位置 最后,我决定使用go而不是C,但是在移植代码时,我遇到了一些问题。据我所知,time.Parse()没有给我任何从现有字符串中解析的选项
s := `10.0.0.1 Jan 11 2014 10:00:00 hello`
在C语言中,就地解析是相当容易的。首先,我在字符串中找到指向日期的指针,然后使用strtime()尽可能多地使用它。这是可能的,因为调用后strptime()将返回字符串中的位置
最后,我决定使用go而不是C,但是在移植代码时,我遇到了一些问题。据我所知,time.Parse()没有给我任何从现有字符串中解析的选项(尽管这可以通过切片来解决),也没有指示它在从字符串中解析日期时消耗了多少原始字符串
是否有任何优雅的方法,我可以将字符串中的日期/时间解析出来,而不必首先将DATE时间提取到一个精确的切片中,例如返回解析后提取的字符数?
< P>也许你应该考虑使用正则表达式来分割日志行,例如:package main
import "fmt"
import "time"
import "regexp"
func main() {
s := "10.0.0.1 Jan 11 2014 10:00:00 hello"
r := regexp.MustCompile("^([^/w]+) ([a-zA-Z]+ [0-9]{1,2} [0-9]{4} [0-9]{1,2}:[0-9]{2}:[0-9]{2}) (.*)")
m := r.FindStringSubmatch(s)
if len(m) >= 4 {
fmt.Println("IP:", m[1])
fmt.Println("Timestamp:", m[2])
fmt.Println("Message:", m[3])
t, err := time.Parse("Jan 02 2006 15:04:05", m[2])
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println("Parsed Time:",t)
}
} else {
fmt.Println("Regexp mismatch!")
}
}
不幸的是,
time.Parse
方法无法告诉您它解析了多少个字符,因此我们需要研究其他优雅的解决方案。在解析日志语句的示例中,正如@rob74所建议的,使用正则表达式是一种相当优雅的策略。以下示例为简洁起见忽略了错误:
var r = regexp.MustCompile(`^((?:\d{1,3}\.){3}\d{1,3}) ([a-zA-Z]{3} \d{1,2} \d{4} \d{1,2}:\d{2}:\d{2}) (.*)`)
const longForm = "Jan 02 2006 15:04:05"
func parseRegex(s string) (ip, msg string, t time.Time) {
m := r.FindStringSubmatch(s)
t, _ = time.Parse(longForm, m[2])
ip, msg = m[1], m[3]
return ip, msg, t
}
基准测试表明,上述正则表达式的效率大约是我机器上@rob74示例的两倍,每秒解析大约100000行:
BenchmarkParseRegex 100000 17130 ns/op
BenchmarkParseRegexRob74 50000 32788 ns/op
但是,如果改用strings.SplitN
,我们可以使解决方案更简短、更高效。例如:
func parseSplit(s string) (ip, msg string, t time.Time) {
parts := strings.SplitN(s, " ", 6)
t, _ = time.Parse(longForm, strings.Join(parts[1:5], " "))
ip, msg = parts[0], parts[5]
return ip, msg, t
}
这将在前5个空格上拆分字符串,并将剩余字符串(消息部分)放入最后的部分切片元素中。这不是很优雅,因为我们依赖于日期格式中的空格数量,但是我们可以通过编程方式计算日期格式字符串中的空格,以获得更通用的解决方案。让我们看看这与我们的正则表达式解决方案相比如何:
BenchmarkParseRegex 100000 17130 ns/op
BenchmarkParseSplit 500000 3557 ns/op
事实证明,相比之下,这是相当有利的。使用SplitN
的速度大约是使用正则表达式的五倍,并且仍然可以生成简洁易读的代码。它这样做的代价是为片分配使用稍多的内存。1<代码>时间。解析
允许解析/跳过固定的“噪音”。2.在第一个空间中分割你的线条实在是太简单了,我认为这是你正在寻找的优雅的解决方案。够公平的,但是约会后的噪音呢?因为我想在数据中的精确位置继续解析,所以我需要知道time.Parse在切片中的结束位置。