Phân tích chuỗi thời gian
Thuộc phần Logic và luồng điều khiển trong hành trình GO của Coddy. Bài học 61 trên 68.
Đôi khi, bạn sẽ nhận được thông tin ngày giờ dưới dạng chuỗi và cần chuyển đổi chúng thành đối tượng time.Time để xử lý. Go cung cấp hàm time.Parse để thực hiện việc chuyển đổi này.
Hàm time.Parse hoạt động ngược với việc định dạng: hàm nhận một chuỗi bố cục và một chuỗi thời gian, rồi trả về một đối tượng time.Time:
dateString := "2023-10-26"
parsedTime, err := time.Parse("2006-01-02", dateString)
if err != nil {
fmt.Println("Error parsing time:", err)
} else {
fmt.Println(parsedTime)
}Tương tự như khi định dạng, bạn dùng các thành phần ngày tham chiếu giống nhau trong chuỗi định dạng. Chuỗi định dạng "2006-01-02" cho Go biết rằng chuỗi đầu vào theo định dạng YYYY-MM-DD. Chuỗi định dạng phải khớp chính xác với định dạng của chuỗi đầu vào.
Hãy nhớ rằng time.Parse trả về hai giá trị: đối tượng time.Time đã phân tích và một lỗi. Luôn kiểm tra lỗi để đảm bảo việc phân tích thành công, vì chuỗi ngày không hợp lệ hoặc bố cục không khớp sẽ khiến việc phân tích thất bại.
Thử thách
DễTạo trình phân tích tệp nhật ký để chuyển đổi chuỗi dấu thời gian từ nhiều định dạng khác nhau thành đối tượng time.Time để phân tích. Thử thách này sẽ kiểm tra khả năng sử dụng time.Parse với các mẫu bố cục khác nhau để xử lý nhiều định dạng ngày giờ thường gặp trong nhật ký hệ thống.
Lưu ý quan trọng: Vì thông báo nhật ký và mẫu bố cục có thể chứa dấu cách, bạn cần dùng bufio.Scanner để đọc toàn bộ dòng đầu vào. Hàm fmt.Scanln dừng đọc ở dấu cách đầu tiên, khiến các mục nhật ký và mẫu bố cục có dấu cách bị lỗi. Hãy dùng bufio.NewScanner(os.Stdin) và gọi scanner.Scan(), sau đó gọi scanner.Text() để đọc đầy đủ từng dòng.
Bạn sẽ nhận hai đầu vào:
- Một chuỗi chứa các mục nhật ký theo định dạng
"timestamp1:message1,timestamp2:message2,timestamp3:message3"(ví dụ:"2023-10-26:System startup,2023/12/25:Holiday shutdown,Jan 15 2024:Maintenance window") - Một chuỗi chứa các mẫu bố cục được phân tách bằng dấu phẩy theo định dạng
"layout1,layout2,layout3"(ví dụ:"2006-01-02,2006/01/02,Jan 2 2006")
Nhiệm vụ của bạn là:
- Dùng
bufio.Scannerđể đọc đúng các dòng đầu vào, xử lý dấu cách trong thông báo nhật ký và mẫu bố cục - Tách đầu vào thứ nhất theo dấu phẩy để lấy từng mục nhật ký
- Với mỗi mục nhật ký, tách theo dấu hai chấm để trích xuất chuỗi dấu thời gian và thông báo
- Tách đầu vào thứ hai theo dấu phẩy để lấy các mẫu bố cục
- Hiển thị tiêu đề ứng dụng:
"=== LOG TIMESTAMP PARSER ===" - Hiển thị trạng thái phân tích:
"Processing log entries with multiple timestamp formats..." - Với mỗi mục nhật ký, thử phân tích dấu thời gian bằng từng mẫu bố cục cho đến khi thành công:
- Thử từng mẫu bố cục với
time.Parsecho đến khi phân tích thành công, tức là không có lỗi - Khi thành công, hiển thị:
"Parsed: [timestamp_string] -> [parsed_time_object] (using layout: [successful_layout])" - Đồng thời hiển thị:
" Message: [log_message]" - Nếu không có mẫu bố cục nào phù hợp với dấu thời gian, hiển thị:
"Failed to parse: [timestamp_string] - no matching layout found"
- Thử từng mẫu bố cục với
- Sau khi xử lý tất cả mục, hiển thị thống kê phân tích:
"=== PARSING RESULTS ===""Total log entries processed: [number_of_entries]""Successfully parsed timestamps: [number_of_successful_parses]""Failed parsing attempts: [number_of_failed_parses]"
- Hiển thị thống kê mức độ sử dụng mẫu bố cục:
"Layout pattern usage:"- Với mỗi mẫu bố cục:
" [layout_pattern]: [number_of_times_used] times"
- Nếu có dấu thời gian được phân tích thành công, hiển thị phần phân tích theo trình tự thời gian:
"=== CHRONOLOGICAL ANALYSIS ===""Earliest timestamp: [earliest_parsed_time]""Latest timestamp: [latest_parsed_time]""Time span covered: [time_difference_description]"
- Hiển thị thông báo hoàn tất:
"Log parsing completed - timestamps converted to time objects"
Dùng gói time cho các thao tác phân tích, gói strings để tách chuỗi đầu vào, các gói bufio và os để xử lý đầu vào đúng cách, cùng gói fmt để định dạng đầu ra. Hãy nhớ rằng time.Parse trả về cả đối tượng time.Time lẫn một lỗi, bạn phải kiểm tra lỗi để xác định việc phân tích có thành công hay không. Khi một mẫu bố cục không phân tích được, hãy thử mẫu tiếp theo cho đến khi tìm được mẫu phù hợp hoặc đã thử hết các lựa chọn. Thử thách này minh họa cách xử lý nhiều định dạng dấu thời gian trong các tình huống xử lý nhật ký thực tế.
Tự làm thử
package main
import (
"bufio"
"fmt"
"os"
"strings"
"time"
)
func main() {
// Tạo scanner để đọc các dòng đầu vào
scanner := bufio.NewScanner(os.Stdin)
// Đọc các mục nhật ký
scanner.Scan()
logEntries := scanner.Text()
// Đọc các mẫu định dạng
scanner.Scan()
layoutPatterns := scanner.Text()
// Phân tích cú pháp đầu vào
entries := strings.Split(logEntries, ",")
layouts := strings.Split(layoutPatterns, ",")
// Khởi tạo các bộ đếm để thống kê
totalEntries := len(entries)
successfulParses := 0
failedParses := 0
layoutUsage := make(map[string]int)
var parsedTimes []time.Time
// TODO: Viết code của bạn bên dưới
// 1. Hiển thị tiêu đề ứng dụng
// 2. Hiển thị trạng thái xử lý
// 3. Xử lý từng mục nhật ký:
// - Tách mục theo ":" để lấy dấu thời gian và thông điệp
// - Thử từng mẫu định dạng cho đến khi tìm được mẫu phù hợp
// - Hiển thị kết quả phân tích cú pháp
// - Cập nhật số liệu thống kê
// 4. Hiển thị số liệu thống kê về quá trình phân tích cú pháp
// 5. Hiển thị số liệu thống kê về việc sử dụng các mẫu định dạng
// 6. Nếu đã phân tích cú pháp các dấu thời gian, hiển thị kết quả phân tích theo thứ tự thời gian
// 7. Hiển thị thông báo hoàn tất
}Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Logic và luồng điều khiển
1Luồng điều khiển nâng cao
Switch với `fallthrough`Thoát khỏi vòng lặp lồng nhauTiếp tục một vòng lặp cụ thểCâu lệnh `goto`Ôn tập: điều khiển vòng lặp nâng cao4Dự án: Danh sách việc cần làm đơn giản
Thiết lập dự ánThêm một việc cần làm7Xử lý lỗi chuyên sâu
Kiểu lỗi tùy chỉnhBọc lỗi bằng `%w`Gỡ bọc lỗi bằng `errors.Is`Gỡ bọc lỗi bằng `errors.As`Tìm hiểu `panic`Sử dụng `recover`Ôn tập: phép chia an toàn10Làm việc với thời gian
Lấy thời gian hiện tạiTạo thời điểm cụ thểĐịnh dạng thời gianPhân tích chuỗi thời gianKhoảng thời gianPhép tính thời gianTạm dừng và bộ đánh dấu thời gianÔn tập: Bộ hẹn giờ đơn giản2Struct và phương thức
Định nghĩa phương thức cho structReceiver giá trịReceiver con trỏChọn receiverPhương thức và hàmÔn tập: hành vi của struct5Tìm hiểu chuyên sâu về map
Map chứa structCon trỏ làm giá trị của mapKiểm tra map nilSo sánh các mapÔn tập: bộ đếm tần suất từ8Dự án: Quản lý hàng tồn kho đơn giản
Tổng quan dự ánKiểm tra hàng tồn kho3Interface (cơ bản)
Interface là gì?Định nghĩa interfaceTriển khai interfaceDùng kiểu interfaceInterface rỗngKhẳng định kiểuType switchÔn tập: hình dạng và hành viTự luyện tập: Trình biên dịch Go online