каждая строка начинается с даты формата dd.MM.YYYY.
Ваша задача – написать функцию ExtractLog(inputFileName string, start, end time.Time) ([]string, error), которая вернет строки “лога”, созданные в указанный диапазон времени [start..end]
Формат вывода
Если в процессе работы возникает любая ошибка, то необходимо вернуть nil, err.
Если ошибок нет, то возвращайте nil в качестве значения ошибки.
Если ни одна строка не попала в указанный диапазон, то должна также вернуться произвольная ошибка.
go
type LogEntry struct {
Timestamp time.Time
Message string
}
Теперь можем написать функцию `ExtractLog`, которая будет отвечать за чтение файла и фильтрацию строк по диапазону времени:
go
func ExtractLog(inputFileName string, start, end time.Time) ([]string, error) {
file, err := os.Open(inputFileName)
if err != nil {
return nil, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
logEntries := make([]LogEntry, 0)
for scanner.Scan() {
line := scanner.Text()
logEntry, err := parseLogEntry(line)
if err != nil {
return nil, err
}
logEntries = append(logEntries, logEntry)
}
if err := scanner.Err(); err != nil {
return nil, err
}
filteredEntries := filterLogEntries(logEntries, start, end)
if len(filteredEntries) == 0 {
return nil, fmt.Errorf("no entries within the specified range")
}
result := make([]string, len(filteredEntries))
for i, entry := range filteredEntries {
result[i] = entry.Message
}
return result, nil
}
В функции `ExtractLog` мы сначала открываем файл и проверяем, не возникла ли ошибка при его открытии. Если возникла, то возвращаем nil и эту ошибку. Затем мы создаем новый сканер для файла и идем по всем его строкам с помощью цикла `for scanner.Scan()`.
Внутри цикла мы считываем каждую строку из файла и пытаемся преобразовать ее в структуру типа `LogEntry` с помощью функции `parseLogEntry`. Если в процессе парсинга возникла ошибка, то мы возвращаем nil и эту ошибку. В противном случае, добавляем прочитанную структуру в список `logEntries`.
После завершения цикла мы проверяем, не возникала ли ошибка при сканировании файла со сканером. Если в процессе сканирования случилась какая-то ошибка, то мы возвращаем nil и эту ошибку.
Затем мы фильтруем список `logEntries`, оставляя только те записи, время создания которых попадает в указанный диапазон [start..end]. Функцию `filterLogEntries` мы реализуем позже.
Если после фильтрации список `logEntries` пуст, то мы возвращаем nil и произвольную ошибку "no entries within the specified range".
Если же список `logEntries` не пуст, то создаем новый список `result` и копируем в него только значения полей `Message` из отфильтрованных записей. Затем возвращаем этот список `result` и nil в качестве ошибки.
Теперь важно реализовать функцию `parseLogEntry`, которая будет преобразовывать каждую строку лога в объект типа `LogEntry`. Для этого мы можем использовать регулярные выражения:
go
func parseLogEntry(line string) (LogEntry, error) {
re := regexp.MustCompile(`(d{2}.d{2}.d{4})s+(.+)`)
matches := re.FindStringSubmatch(line)
if len(matches) != 3 {
return LogEntry{}, fmt.Errorf("unable to parse log entry: %s", line)
}
timestamp, err := time.Parse("02.01.2006", matches[1])
if err != nil {
return LogEntry{}, err
}
return LogEntry{
Timestamp: timestamp,
Message: matches[2],
}, nil
}
В функции `parseLogEntry` мы используем регулярное выражение `(d{2}.d{2}.d{4})s+(.+)` для извлечения даты и сообщения из строки. Затем мы проверяем, что размер массива `matches` равен 3. Если он отличается, то возвращаем пустую структуру `LogEntry` и ошибку "unable to parse log entry".
Если размер массива `matches` равен 3, то мы парсим дату из первого элемента массива с помощью функции `time.Parse`. Если в процессе парсинга происходит ошибка, то возвращаем пустую структуру `LogEntry` и эту ошибку.
В противном случае, возвращаем структуру `LogEntry`, сформированную из найденных значений.
Теперь осталось реализовать функцию `filterLogEntries`, которая будет отбирать записи из списка `logEntries` в указанном временном диапазоне:
go
func filterLogEntries(entries []LogEntry, start, end time.Time) []LogEntry {
result := make([]LogEntry, 0)
for _, entry := range entries {
if entry.Timestamp.After(start) && entry.Timestamp.Before(end) {
result = append(result, entry)
}
}
return result
}
В функции `filterLogEntries` мы идем по каждой записи из входного списка `entries` и проверяем, находится ли ее время создания (`entry.Timestamp`) в указанном временном диапазоне. Если да, то добавляем эту запись в результирующий список `result`.
После завершения обхода всех записей возвращаем результирующий список `result`.
Теперь мы можем вызвать функцию `ExtractLog` с нужными аргументами и получить список строк лога, созданных в указанном диапазоне времени. Например:
go
logLines, err := ExtractLog("log.txt", time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), time.Date(2021, 12, 31, 23, 59, 59, 999999999, time.UTC))
if err != nil {
log.Fatal(err)
}
fmt.Println(logLines)
В данном примере мы указываем, что интересуют только строки лога, созданные в течение 2021 года. Если в указанном диапазоне времени есть строки лога, результат будет напечатан на экран. В противном случае программа завершится с ошибкой, сообщающей, что нет записей в указанном диапазоне.Нажимая «Регистрация» или «Войти через Google», вы соглашаетесь с Публичной офертой, даете Согласие на обработку персональных данных, а также подтверждаете что вам есть 18 лет
Нажимая «Регистрация» или «Войти через Google», вы соглашаетесь с Публичной офертой, даете Согласие на обработку персональных данных, а также подтверждаете что вам есть 18 лет