Menu
Coddy logo textTech

Podsumowanie — parser plików

Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 58 z 107.

challenge icon

Wyzwanie

Łatwy

Zbudujmy parser plików konfiguracyjnych, który łączy wszystkie techniki obsługi błędów z tego rozdziału. Twój parser będzie obsługiwać różne scenariusze awarii za pomocą własnych typów błędów, błędów znacznikowych, opakowywania błędów oraz prawidłowego sprzątania z użyciem defer.

Rozmieścisz kod w trzech plikach:

  • errors.go: Zdefiniuj infrastrukturę błędów dla parsera.

    Utwórz dwa błędy znacznikowe:

    • ErrEmptyContent z komunikatem "file content is empty"
    • ErrInvalidFormat z komunikatem "invalid configuration format"

    Utwórz własny typ błędu ParseError z polami Line (int) i Message (string). Jego metoda Error() powinna zwracać: parse error at line [Line]: [Message]

  • parser.go: Zbuduj parser konfiguracji z warstwową obsługą błędów.

    Utwórz strukturę ConfigParser z polem logicznym parsed, które będzie śledzić, czy parsowanie zakończyło się powodzeniem.

    Zaimplementuj te metody:

    • NewConfigParser() *ConfigParser – tworzy nowy parser z wartością parsed ustawioną na false
    • ParseLine(lineNum int, line string) error – sprawdza poprawność pojedynczej linii. Jeśli linia nie zawiera znaku =, zwraca *ParseError z numerem linii i komunikatem "missing key-value separator". W przeciwnym razie zwraca nil.
    • Parse(content string) error – główna metoda parsująca, która:
      • Zwraca ErrEmptyContent, jeśli treść jest pusta
      • Zwraca ErrInvalidFormat, jeśli treść nie zawiera co najmniej jednego znaku nowej linii
      • Dzieli treść według znaków nowej linii i wywołuje ParseLine dla każdej linii (numerowanie linii rozpoczyna się od 1)
      • Jeśli ParseLine zwraca błąd, opakowuje go w "parsing configuration: %w" i zwraca
      • W przypadku powodzenia ustawia parsed na true i zwraca nil
    • Status() string – zwraca "ready", jeśli parsed ma wartość true, a w przeciwnym razie "not parsed"
  • main.go: Odczytaj treść konfiguracji i pokaż kompleksowe sprawdzanie błędów.

    Odczytaj dwa wiersze wejściowe, które razem tworzą treść konfiguracji (połącz je znakiem nowej linii). Użyj defer, aby zawsze na końcu wypisać stan parsera, niezależnie od tego, czy operacja się powiedzie, czy nie.

    Po próbie parsowania sprawdź ewentualny błąd za pomocą zarówno errors.Is(), jak i errors.As(), aby przekazać konkretne informacje o przyczynie problemu.

Podane zostaną następujące dane wejściowe:

  • Wiersz 1: Pierwszy wiersz treści konfiguracji
  • Wiersz 2: Drugi wiersz treści konfiguracji

Obsłuż błędy, wypisując konkretne komunikaty:

  • Jeśli errors.Is() znajdzie ErrEmptyContent: wypisz Error: No configuration provided
  • Jeśli errors.Is() znajdzie ErrInvalidFormat: wypisz Error: Configuration must have multiple lines
  • Jeśli errors.As() znajdzie wartość typu *ParseError: wypisz pełny opakowany błąd, a następnie w nowym wierszu wypisz Fix line [Line]: [Message]
  • Jeśli parsowanie się powiedzie: wypisz Configuration parsed successfully

Po obsłużeniu wyniku (powodzenia lub błędu) odroczony komunikat o stanie powinien zostać wypisany w nowym wierszu: Parser status: [status]

Na przykład dla danych host=localhost i port=8080 wynik powinien wyglądać następująco:

Configuration parsed successfully
Parser status: ready

A dla danych host=localhost i invalid line wynik powinien wyglądać następująco:

parsing configuration: parse error at line 2: missing key-value separator
Fix line 2: missing key-value separator
Parser status: not parsed

Spróbuj swoich sił

package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Wczytaj pierwszą linię konfiguracji
	line1, _ := reader.ReadString('\n')
	line1 = line1[:len(line1)-1] // Usuń końcowy znak nowej linii
	
	// Wczytaj drugą linię konfiguracji
	line2, _ := reader.ReadString('\n')
	if len(line2) > 0 && line2[len(line2)-1] == '\n' {
		line2 = line2[:len(line2)-1]
	}
	
	// Połącz obie linie znakiem nowej linii, aby utworzyć treść konfiguracji
	content := line1 + "\n" + line2
	
	// Utwórz nowy parser
	parser := NewConfigParser()
	
	// TODO: Użyj defer, aby na końcu zawsze wypisać stan parsera
	// Format: "Parser status: [status]"
	
	// TODO: Spróbuj przeanalizować treść
	
	// TODO: Obsłuż błędy za pomocą errors.Is() i errors.As()
	// - Jeśli errors.Is() znajdzie ErrEmptyContent: wypisz "Error: No configuration provided"
	// - Jeśli errors.Is() znajdzie ErrInvalidFormat: wypisz "Error: Configuration must have multiple lines"
	// - Jeśli errors.As() znajdzie *ParseError: wypisz pełny błąd wraz z błędami, które opakowuje,
	//   następnie w nowym wierszu wypisz "Fix line [Line]: [Message]"
	// - Jeśli parsowanie się powiedzie: wypisz "Configuration parsed successfully"
	
	_ = errors.Is // wskazówka: użyj errors.Is do obsługi błędów sygnalizacyjnych
	_ = errors.As // wskazówka: użyj errors.As do obsługi niestandardowych typów błędów
	_ = fmt.Println
}

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Go online