Menu
Coddy logo textTech

Rückblick – Dateiparser

Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 58 von 107.

challenge icon

Aufgabe

Einfach

Erstellen wir einen Konfigurationsdatei-Parser, der alle Fehlerbehandlungstechniken aus diesem Kapitel zusammenführt. Dein Parser behandelt mehrere Fehlerszenarien mit benutzerdefinierten Fehlertypen, Sentinel-Fehlern, Fehler-Wrapping und ordnungsgemäßer Bereinigung mithilfe von defer.

Du organisierst deinen Code über drei Dateien:

  • errors.go: Definiere die Fehlerinfrastruktur für den Parser.

    Erstelle zwei Sentinel-Fehler:

    • ErrEmptyContent mit der Meldung "file content is empty"
    • ErrInvalidFormat mit der Meldung "invalid configuration format"

    Erstelle einen benutzerdefinierten Fehlertyp ParseError mit den Feldern Line (int) und Message (string). Seine Methode Error() soll Folgendes zurückgeben: parse error at line [Line]: [Message]

  • parser.go: Erstelle den Konfigurationsparser mit mehrstufiger Fehlerbehandlung.

    Erstelle eine Struktur ConfigParser mit einem booleschen Feld parsed, um zu verfolgen, ob das Parsen erfolgreich abgeschlossen wurde.

    Implementiere diese Methoden:

    • NewConfigParser() *ConfigParser – erstellt einen neuen Parser, bei dem parsed auf false gesetzt ist
    • ParseLine(lineNum int, line string) error – validiert eine einzelne Zeile. Wenn die Zeile kein =-Zeichen enthält, gib einen *ParseError mit der Zeilennummer und der Meldung "missing key-value separator" zurück. Andernfalls gib nil zurück.
    • Parse(content string) error – die Hauptmethode zum Parsen, die:
      • ErrEmptyContent zurückgibt, wenn der Inhalt leer ist
      • ErrInvalidFormat zurückgibt, wenn der Inhalt nicht mindestens ein Zeilenumbruchzeichen enthält
      • den Inhalt anhand von Zeilenumbrüchen aufteilt und für jede Zeile ParseLine aufruft (die Zeilennummern beginnen bei 1)
      • den Fehler mit ParseLine umschließt und zurückgibt, wenn "parsing configuration: %w" einen Fehler zurückgibt
      • parsed bei Erfolg auf true setzt und nil zurückgibt
    • Status() string – gibt "ready" zurück, wenn parsed den Wert true hat, andernfalls "not parsed"
  • main.go: Lies den Konfigurationsinhalt ein und demonstriere eine umfassende Fehlerprüfung.

    Lies zwei Eingabezeilen ein, die zusammen den Konfigurationsinhalt bilden (verbinde sie mit einem Zeilenumbruch). Verwende defer, um unabhängig von Erfolg oder Fehler am Ende immer den Status des Parsers auszugeben.

    Untersuche nach dem Versuch zu parsen jeden Fehler mit errors.Is() und errors.As(), um abhängig von der Fehlerursache eine spezifische Rückmeldung zu geben.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Erste Zeile des Konfigurationsinhalts
  • Zeile 2: Zweite Zeile des Konfigurationsinhalts

Behandle Fehler mit spezifischen Meldungen:

  • Wenn errors.Is() ErrEmptyContent findet: Gib Error: No configuration provided aus
  • Wenn errors.Is() ErrInvalidFormat findet: Gib Error: Configuration must have multiple lines aus
  • Wenn errors.As() einen *ParseError findet: Gib zuerst den vollständig umschlossenen Fehler aus und anschließend in einer neuen Zeile Fix line [Line]: [Message]
  • Wenn das Parsen erfolgreich ist: Gib Configuration parsed successfully aus

Nach der Verarbeitung des Ergebnisses (Erfolg oder Fehler) soll der aufgeschobene Status in einer neuen Zeile ausgegeben werden: Parser status: [status]

Wenn beispielsweise host=localhost und port=8080 angegeben werden, sollte deine Ausgabe wie folgt aussehen:

Configuration parsed successfully
Parser status: ready

Und bei host=localhost und invalid line sollte deine Ausgabe wie folgt aussehen:

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

Probier es selbst

package main

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

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Erste Zeile der Konfiguration lesen
	line1, _ := reader.ReadString('\n')
	line1 = line1[:len(line1)-1] // Abschließenden Zeilenumbruch entfernen
	
	// Zweite Zeile der Konfiguration lesen
	line2, _ := reader.ReadString('\n')
	if len(line2) > 0 && line2[len(line2)-1] == '\n' {
		line2 = line2[:len(line2)-1]
	}
	
	// Die beiden Zeilen mit einem Zeilenumbruch verbinden, um den Konfigurationsinhalt zu bilden
	content := line1 + "\n" + line2
	
	// Einen neuen Parser erstellen
	parser := NewConfigParser()
	
	// TODO: defer verwenden, um am Ende immer den Status des Parsers auszugeben
	// Format: "Parser status: [status]"
	
	// TODO: Versuchen, den Inhalt zu parsen
	
	// TODO: Fehler mit errors.Is() und errors.As() behandeln
	// - Wenn errors.Is() ErrEmptyContent findet: "Error: No configuration provided" ausgeben
	// - Wenn errors.Is() ErrInvalidFormat findet: "Error: Configuration must have multiple lines" ausgeben
	// - Wenn errors.As() einen *ParseError findet: den vollständigen gewrappten Fehler ausgeben,
	//   dann in einer neuen Zeile "Fix line [Line]: [Message]" ausgeben
	// - Wenn das Parsen erfolgreich ist: "Configuration parsed successfully" ausgeben
	
	_ = errors.Is // Hinweis: errors.Is für Sentinel-Fehler verwenden
	_ = errors.As // Hinweis: errors.As für benutzerdefinierte Fehlertypen verwenden
	_ = fmt.Println
}

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Go-Compiler