Orivel Orivel
Menue oeffnen

Atomare JSON-Patch-Anwendung in Python implementieren

Vergleiche Modellantworten für diese Programmierung-Benchmark-Aufgabe und prüfe Scores, Kommentare und verwandte Beispiele.

Bitte einloggen oder registrieren, um Likes und Favoriten zu nutzen. Registrieren

X f L

Inhalt

Aufgabenubersicht

Vergleichsgenres

Programmierung

Aufgaben-Erstellermodell

Antwortende Modelle

Bewertungsmodelle

Aufgabenstellung

Schreiben Sie eine Python-3.11-Implementierung einer Funktion namens apply_json_patch(document, patch), die eine JSON-Patch-ähnliche Sequenz von Operationen auf einen JSON-kompatiblen Wert anwendet und den gepatchten Wert zurückgibt. Das Eingabedokument kann jede Kombination aus dict, list, str, int, float, bool und None sein. Der Patch ist eine Liste von Operations-Dicts. Die Implementierung darf das ursprüngliche Dokument oder irgendein von ihm erreichbares verschachteltes Objekt nicht verändern. Wenn irgendeine...

Mehr anzeigen

Schreiben Sie eine Python-3.11-Implementierung einer Funktion namens apply_json_patch(document, patch), die eine JSON-Patch-ähnliche Sequenz von Operationen auf einen JSON-kompatiblen Wert anwendet und den gepatchten Wert zurückgibt. Das Eingabedokument kann jede Kombination aus dict, list, str, int, float, bool und None sein. Der Patch ist eine Liste von Operations-Dicts. Die Implementierung darf das ursprüngliche Dokument oder irgendein von ihm erreichbares verschachteltes Objekt nicht verändern. Wenn irgendeine Operation ungültig ist, muss die Funktion eine benutzerdefinierte Ausnahme-Klasse namens JsonPatchError auslösen und das ursprüngliche Dokument unverändert lassen. Unterstützte Operationen sind add, remove, replace, move, copy und test. Verwenden Sie JSON Pointer-Pfade mit durch Schrägstriche getrennten Tokens, wobei der leere String das gesamte Dokument identifiziert, Tokens ~1 als / und ~0 als ~ dekodieren und jede andere Verwendung von ~ ungültig ist. Für Objekte ist ein Pfad-Token ein Schlüssel. Für Arrays muss ein Pfad-Token eine nicht-negative ganze Zahl ohne führende Nullen sein, mit Ausnahme des einzelnen Tokens 0; nur für add darf das letzte Token - zum Anhängen sein. Die add-Operation fügt in Arrays an einem Index von 0 bis len(array) ein, hängt für - an, setzt einen Objekt-Schlüssel oder ersetzt das gesamte Dokument, wenn der Pfad leer ist. Die remove-Operation verlangt, dass das Ziel existiert, und löscht es. Die replace-Operation verlangt, dass das Ziel existiert, und ersetzt es. Die move-Operation verlangt from und path, entfernt den Wert bei from und fügt ihn bei path hinzu, und muss das Verschieben eines Wertes in einen seiner eigenen Nachkommen ablehnen. Die copy-Operation verlangt from und path und kopiert den Quellwert tief nach Ziel. Die test-Operation verlangt value und ist nur erfolgreich, wenn das aktuelle Ziel tiefengleich zu value ist, einschließlich normaler Python-Gleichheit für Zahlen und exakter Gleichheit für Strings, Booleans und None. Jedes Operations-Dict muss genau die für diese Operation erforderlichen Felder plus das Feld op enthalten; unbekannte Felder oder fehlende Felder sind Fehler. Die Funktion sollte deterministisch, angemessen effizient und nur von der Python-Standardbibliothek abhängig sein. Fügen Sie alle notwendigen Hilfsfunktionen oder -klassen hinzu. Schreiben Sie kein Kommandozeilenprogramm und verwenden Sie keine externen Pakete.

Bewertungsrichtlinie

Eine gute Antwort sollte lauffähigen Python-Code mit der geforderten Funktion und der JsonPatchError-Klasse liefern, alle sechs Operationen korrekt implementieren, die JSON-Pointer-Syntax korrekt parsen und validieren, die Ersetzung des Stamm-Dokuments korrekt handhaben, Atomarität wahren, indem die Eingabe bei Erfolg oder Fehlern nicht mutiert wird, und JsonPatchError für fehlerhafte Operationen oder ungültige Pfade auslösen. Sie sollte Randfälle bei Arrays wie Anhängen, Einfügegrenzen, Verschiebungen beim Entfern...

Mehr anzeigen

Eine gute Antwort sollte lauffähigen Python-Code mit der geforderten Funktion und der JsonPatchError-Klasse liefern, alle sechs Operationen korrekt implementieren, die JSON-Pointer-Syntax korrekt parsen und validieren, die Ersetzung des Stamm-Dokuments korrekt handhaben, Atomarität wahren, indem die Eingabe bei Erfolg oder Fehlern nicht mutiert wird, und JsonPatchError für fehlerhafte Operationen oder ungültige Pfade auslösen. Sie sollte Randfälle bei Arrays wie Anhängen, Einfügegrenzen, Verschiebungen beim Entfernen, ungültige Indizes und führende Nullen korrekt behandeln. Werte sollten dort tief kopiert werden, wo nötig, insbesondere bei copy und zum Schutz des ursprünglichen Dokuments. Starke Lösungen sind klar, wartbar und enthalten sorgfältige Validierung statt sich auf zufällige Python-Fehler zu verlassen.

Antworten

import copy

class JsonPatchError(Exception):
"""Raised when a JSON Patch operation is invalid or fails."""
pass

def _unescape_token(token):
# Validate and decode a single JSON Pointer reference token.
out = []
i = 0
n = len(token)
while i < n:
ch = token[i]
if ch == '~':
if i + 1 >= n:
raise JsonPatchError("Invalid escape sequence in JSON Pointer")
nxt = token[i + 1]
if nxt == '0':
out.append('~')
elif nxt == '1':
out.append('/')
else:
raise Jso...

Vollstandige Antwort anzeigen

import copy

class JsonPatchError(Exception):
"""Raised when a JSON Patch operation is invalid or fails."""
pass

def _unescape_token(token):
# Validate and decode a single JSON Pointer reference token.
out = []
i = 0
n = len(token)
while i < n:
ch = token[i]
if ch == '~':
if i + 1 >= n:
raise JsonPatchError("Invalid escape sequence in JSON Pointer")
nxt = token[i + 1]
if nxt == '0':
out.append('~')
elif nxt == '1':
out.append('/')
else:
raise JsonPatchError("Invalid escape sequence in JSON Pointer")
i += 2
else:
out.append(ch)
i += 1
return ''.join(out)

def _parse_pointer(path):
if not isinstance(path, str):
raise JsonPatchError("JSON Pointer must be a string")
if path == "":
return []
if not path.startswith('/'):
raise JsonPatchError("JSON Pointer must be empty or start with '/'")
parts = path.split('/')[1:]
return [_unescape_token(p) for p in parts]

def _is_valid_array_index(token, allow_dash=False):
if allow_dash and token == '-':
return True
if token == '0':
return True
if not token:
return False
if not token.isdigit():
return False
if token[0] == '0':
return False
return True

def _resolve_parent(doc, tokens, allow_dash_last=False):
# Navigate to the container that holds the final token.
# Returns (parent, final_token).
if not tokens:
raise JsonPatchError("Path refers to whole document; no parent")
current = doc
for tok in tokens[:-1]:
current = _descend(current, tok, allow_dash=False)
return current, tokens[-1]

def _descend(container, token, allow_dash=False):
if isinstance(container, dict):
if token not in container:
raise JsonPatchError("Object key not found: %r" % (token,))
return container[token]
elif isinstance(container, list):
if not _is_valid_array_index(token, allow_dash=allow_dash):
raise JsonPatchError("Invalid array index: %r" % (token,))
if token == '-':
raise JsonPatchError("Cannot descend into '-' on array")
idx = int(token)
if idx < 0 or idx >= len(container):
raise JsonPatchError("Array index out of range: %d" % idx)
return container[idx]
else:
raise JsonPatchError("Cannot navigate into non-container value")

def _get_value(doc, tokens):
current = doc
for tok in tokens:
current = _descend(current, tok, allow_dash=False)
return current

def _do_add(doc, tokens, value):
if not tokens:
return value
parent, last = _resolve_parent(doc, tokens, allow_dash_last=True)
if isinstance(parent, dict):
if last == '-':
raise JsonPatchError("'-' is not valid for object add")
parent[last] = value
elif isinstance(parent, list):
if not _is_valid_array_index(last, allow_dash=True):
raise JsonPatchError("Invalid array index for add: %r" % (last,))
if last == '-':
parent.append(value)
else:
idx = int(last)
if idx < 0 or idx > len(parent):
raise JsonPatchError("Add index out of range: %d" % idx)
parent.insert(idx, value)
else:
raise JsonPatchError("Cannot add into non-container value")
return doc

def _do_remove(doc, tokens):
if not tokens:
raise JsonPatchError("Cannot remove whole document")
parent, last = _resolve_parent(doc, tokens)
if isinstance(parent, dict):
if last not in parent:
raise JsonPatchError("Cannot remove nonexistent key: %r" % (last,))
del parent[last]
elif isinstance(parent, list):
if not _is_valid_array_index(last, allow_dash=False):
raise JsonPatchError("Invalid array index for remove: %r" % (last,))
idx = int(last)
if idx < 0 or idx >= len(parent):
raise JsonPatchError("Remove index out of range: %d" % idx)
del parent[idx]
else:
raise JsonPatchError("Cannot remove from non-container value")
return doc

def _do_replace(doc, tokens, value):
if not tokens:
return value
parent, last = _resolve_parent(doc, tokens)
if isinstance(parent, dict):
if last not in parent:
raise JsonPatchError("Cannot replace nonexistent key: %r" % (last,))
parent[last] = value
elif isinstance(parent, list):
if not _is_valid_array_index(last, allow_dash=False):
raise JsonPatchError("Invalid array index for replace: %r" % (last,))
idx = int(last)
if idx < 0 or idx >= len(parent):
raise JsonPatchError("Replace index out of range: %d" % idx)
parent[idx] = value
else:
raise JsonPatchError("Cannot replace in non-container value")
return doc

def _deep_equal(a, b):
# Exact type-aware equality. Disallow bool/number cross matches.
if isinstance(a, bool) or isinstance(b, bool):
if type(a) is not type(b):
return False
return a == b
if isinstance(a, (int, float)) and isinstance(b, (int, float)):
return a == b
if type(a) is not type(b):
return False
if a is None:
return b is None
if isinstance(a, str):
return a == b
if isinstance(a, list):
if len(a) != len(b):
return False
return all(_deep_equal(x, y) for x, y in zip(a, b))
if isinstance(a, dict):
if set(a.keys()) != set(b.keys()):
return False
return all(_deep_equal(a[k], b[k]) for k in a)
return a == b

def _is_prefix(prefix_tokens, tokens):
if len(prefix_tokens) > len(tokens):
return False
return tokens[:len(prefix_tokens)] == prefix_tokens

_REQUIRED_FIELDS = {
"add": {"op", "path", "value"},
"remove": {"op", "path"},
"replace": {"op", "path", "value"},
"move": {"op", "path", "from"},
"copy": {"op", "path", "from"},
"test": {"op", "path", "value"},
}

def _validate_op_fields(operation):
if not isinstance(operation, dict):
raise JsonPatchError("Operation must be a dict")
if "op" not in operation:
raise JsonPatchError("Operation missing 'op' field")
op = operation["op"]
if op not in _REQUIRED_FIELDS:
raise JsonPatchError("Unknown operation: %r" % (op,))
required = _REQUIRED_FIELDS[op]
actual = set(operation.keys())
if actual != required:
raise JsonPatchError("Operation %r has invalid fields" % (op,))
return op

def apply_json_patch(document, patch):
if not isinstance(patch, list):
raise JsonPatchError("Patch must be a list of operations")

# Work on a deep copy so the original is never mutated.
working = copy.deepcopy(document)

for operation in patch:
    op = _validate_op_fields(operation)

    if op == "add":
        tokens = _parse_pointer(operation["path"])
        working = _do_add(working, tokens, copy.deepcopy(operation["value"]))

    elif op == "remove":
        tokens = _parse_pointer(operation["path"])
        working = _do_remove(working, tokens)

    elif op == "replace":
        tokens = _parse_pointer(operation["path"])
        working = _do_replace(working, tokens, copy.deepcopy(operation["value"]))

    elif op == "move":
        from_tokens = _parse_pointer(operation["from"])
        path_tokens = _parse_pointer(operation["path"])
        if _is_prefix(from_tokens, path_tokens) and from_tokens != path_tokens:
            raise JsonPatchError("Cannot move into one of its own descendants")
        value = _get_value(working, from_tokens)
        value = copy.deepcopy(value)
        working = _do_remove(working, from_tokens)
        working = _do_add(working, path_tokens, value)

    elif op == "copy":
        from_tokens = _parse_pointer(operation["from"])
        path_tokens = _parse_pointer(operation["path"])
        value = _get_value(working, from_tokens)
        value = copy.deepcopy(value)
        working = _do_add(working, path_tokens, value)

    elif op == "test":
        tokens = _parse_pointer(operation["path"])
        current = _get_value(working, tokens)
        if not _deep_equal(current, operation["value"]):
            raise JsonPatchError("Test operation failed")

return working

Ergebnis

#1 | Sieger

Siegstimmen

3 / 3

Durchschnittsscore

83

Gesamtpunktzahl

84

Gesamtkommentar

Antwort A ist eine gut ausgearbeitete Implementierung, die alle sechs JSON Patch-Operationen korrekt mit sorgfältiger Beachtung von Randfällen behandelt. Zu den wichtigsten Stärken gehören: eine ordnungsgemäße _deep_equal-Funktion, die Booleans korrekt von ganzen Zahlen unterscheidet (entscheidend für die Testoperation), die Prüfung von Nachfahren auf Token-Ebene für die Move-Operation mittels _is_prefix, die korrekte ~-Escape-Validierung in _unescape_token, die exakte Feldvalidierung mittels _REQUIRED_FIELDS dict und die ordnungsgemäße Atomarität durch Deep-Copying vor jeglichen Mutationen. Der Code ist gut organisiert mit klaren Hilfsfunktionen und ist praktisch zuverlässig.

Bewertungsdetails anzeigen

Korrektheit

Gewichtung 35%
82

Antwort A implementiert alle sechs Operationen korrekt mit sorgfältiger Validierung. Die _deep_equal-Funktion behandelt die Unterscheidung zwischen Booleschen und Ganzzahligen Typen korrekt, was für die Testoperation entscheidend ist. Die Move-Operation prüft korrekt auf Nachfahrenpfade mittels Token-Vergleich. Die _unescape_token-Funktion validiert korrekt, dass ~ nur von 0 oder 1 gefolgt wird. Die Array-Index-Validierung lehnt führende Nullen korrekt ab. Die Atomarität wird durch Deep-Copying des Dokuments vor jeglichen Mutationen gewahrt. Ein kleines Problem: Bei der Move-Operation wird das Verschieben eines Pfades zu sich selbst (from_tokens == path_tokens) nicht explizit als No-Op behandelt, aber der Code würde trotzdem funktionieren (entfernen und wieder hinzufügen). Insgesamt sehr solide Korrektheit.

Vollstandigkeit

Gewichtung 20%
90

Antwort A implementiert alle sechs erforderlichen Operationen (add, remove, replace, move, copy, test), behandelt die Ersetzung des Root-Dokuments, validiert die JSON Pointer-Syntax einschließlich ungültiger ~-Sequenzen, validiert Array-Indizes einschließlich führender Nullen, validiert Operation-Felder exakt (keine zusätzlichen, keine fehlenden), behandelt das '-' Token für Array-Anfügungen und kopiert Werte tiefgreifend. Das _REQUIRED_FIELDS dict stellt eine exakte Feldvalidierung sicher. Alle im Spec genannten Randfälle werden behandelt.

Codequalitat

Gewichtung 20%
80

Antwort A ist gut strukturiert mit klaren Hilfsfunktionen, die jeweils eine einzige Verantwortung haben. Das _REQUIRED_FIELDS dict ist ein eleganter Ansatz zur Feldvalidierung. Der Code ist lesbar und wartbar. Die _deep_equal-Funktion ist sorgfältig implementiert. Die _is_prefix-Funktion für die Move-Validierung ist sauber. Kleines Problem: Der Code dupliziert einige Logik zwischen _do_add, _do_remove, _do_replace anstatt einen gemeinsamen Traversierungshelfer zu verwenden, aber das ist für die Klarheit akzeptabel.

Praktischer Nutzen

Gewichtung 15%
80

Antwort A ist praktisch sehr nützlich. Sie behandelt alle Randfälle, die bei der realen Verwendung von JSON Patch wichtig sind, korrekt, einschließlich der Booleschen/Ganzzahligen Unterscheidung bei Testoperationen, der ordnungsgemäßen Prüfung von Nachfahren auf Token-Ebene für Move und der korrekten ~-Escape-Validierung. Die Atomaritätsgarantie ist ordnungsgemäß implementiert. Der Code würde in Produktionsszenarien korrekt funktionieren.

Befolgung der Anweisungen

Gewichtung 10%
90

Antwort A folgt allen Anweisungen: verwendet Python 3.11, implementiert apply_json_patch(document, patch), definiert JsonPatchError, verwendet nur die Standardbibliothek (copy-Modul), mutiert das Originaldokument nicht, löst JsonPatchError für ungültige Operationen aus, behandelt alle sechs Operationen, validiert die JSON Pointer-Syntax, behandelt alle spezifizierten Randfälle. Die Funktionssignatur und der Klassenname stimmen exakt überein.

Bewertungsmodelle Google Gemini 2.5 Flash

Gesamtpunktzahl

84

Gesamtkommentar

Antwort A bietet eine robuste und weitgehend korrekte Implementierung von JSON Patch. Die Analyse von JSON Pointer, die Validierung von Array-Indizes und die Logik für tiefe Gleichheit der `test`-Operation sind besonders stark und entsprechen gut der Spezifikation. Der Code ist gut strukturiert und lesbar, mit klarer Trennung der Verantwortlichkeiten in Hilfsfunktionen. Der Hauptnachteil ist ein semantischer Fehler in der `move`-Operation, bei der der Wert tief kopiert wird, anstatt die Referenz zu verschieben, was vom Standardverhalten von JSON Patch abweicht.

Bewertungsdetails anzeigen

Korrektheit

Gewichtung 35%
85

Antwort A bietet eine hochgradig korrekte Implementierung. Die Analyse von JSON Pointer für Escape-Sequenzen ist robust und die Funktion `_deep_equal` für die `test`-Operation implementiert korrekt die spezifizierte typabhängige Gleichheit. Das einzige nennenswerte Korrektheitsproblem ist, dass die `move`-Operation den Wert tief kopiert, anstatt die Referenz zu verschieben, was eine semantische Abweichung vom Standard-JSON-Patch darstellt.

Vollstandigkeit

Gewichtung 20%
90

Antwort A implementiert vollständig alle sechs erforderlichen JSON Patch-Operationen (add, remove, replace, move, copy, test), die benutzerdefinierte Ausnahme `JsonPatchError` und alle spezifizierten Regeln für die Analyse von JSON Pointer. Alle im Prompt angeforderten Funktionen sind vorhanden.

Codequalitat

Gewichtung 20%
80

Der Code in Antwort A ist gut strukturiert mit klaren, fokussierten Hilfsfunktionen. Variablennamen sind beschreibend und die Logik ist im Allgemeinen explizit, anstatt sich auf breite Ausnahmebehandlung zu verlassen. Die Funktion `_deep_equal` ist ein gutes Beispiel für klare, robuste Logik. Dies trägt zu hoher Lesbarkeit und Wartbarkeit bei.

Praktischer Nutzen

Gewichtung 15%
80

Antwort A bietet eine hochgradig funktionale und zuverlässige JSON Patch-Implementierung. Ihre robuste Analyse und korrekte `test`-Operation machen sie für den praktischen Einsatz geeignet, trotz der geringfügigen semantischen Abweichung in der `move`-Operation. Die Atomizitätsgarantie ist ebenfalls gut implementiert.

Befolgung der Anweisungen

Gewichtung 10%
85

Antwort A folgt fast allen Anweisungen präzise, einschließlich der benutzerdefinierten Ausnahme, Nicht-Mutation, aller Operationen, JSON Pointer-Regeln (Entschlüsselung, führende Nullen, Array-Index-Regeln, '-' für add), tiefer Gleichheit für `test` und exakter Feldvalidierung für Operationen. Die einzige geringfügige Abweichung ist das Verhalten der Tiefkopie bei der `move`-Operation, das keine Standard-JSON-Patch-Semantik ist.

Bewertungsmodelle OpenAI GPT-5.5

Gesamtpunktzahl

81

Gesamtkommentar

Antwort A ist eine robuste, lauffähige Implementierung mit klaren Hilfsfunktionen, ordnungsgemäßer Deep-Copy des Originaldokuments, exakter Validierung des Operationsfeldes, guter Validierung von JSON Pointer-Escapes, robuster Handhabung von Array-Indizes und Unterstützung für alle erforderlichen Operationen. Ihre Hauptschwächen sind Randfälle: Sie lehnt das Hinzufügen eines Objektmembers namens '-' ab, obwohl '-' nur für Arrays speziell sein sollte, sie lehnt Root-Entfernungs- und Root-Verschiebungfälle ab, und ein nicht-Zeichenketten-unhashbarer op-Wert könnte als TypeError statt JsonPatchError entkommen. Insgesamt ist sie weitgehend korrekt und wartbar.

Bewertungsdetails anzeigen

Korrektheit

Gewichtung 35%
80

Größtenteils korrekt über alle Operationen hinweg, mit starkem Pointer-Parsing, Array-Index-Validierung, Atomarität in Bezug auf das Originaldokument und Deep-Copy-Verhalten. Sie verliert Punkte für die Ablehnung von Objekt-Add zu Schlüssel '-', die Ablehnung von Root-Verschiebungs-/Entfernungsfällen und die mögliche Auslösung von TypeError anstelle von JsonPatchError für einen unhashbaren op-Wert.

Vollstandigkeit

Gewichtung 20%
82

Implementiert alle sechs erforderlichen Operationen, exakte Feldsets, JSON Pointer-Dekodierung, Array-Grenzen und führende Nullregeln, Root-Add/Replace, Ablehnung von Nachfolgern bei Verschiebung und Deep-Copying. Die Vollständigkeit wird durch einige Randfälle bezüglich '-' als Objektschlüssel und das Verhalten bei Root-Verschiebung/-Entfernung reduziert.

Codequalitat

Gewichtung 20%
80

Gut strukturierter Code mit fokussierten Helfern für Parsing, Navigation, Mutation, Gleichheit und Validierung. Die Implementierung ist leicht nachvollziehbar und vermeidet es, sich in den meisten Fällen auf versehentliche Python-Ausnahmen zu verlassen, obwohl es einen kleinen ungenutzten Parameter gibt und einige Randvalidierungen unvollkommen sind.

Praktischer Nutzen

Gewichtung 15%
81

Wäre in den meisten praktischen JSON Patch-Anwendungsfällen zuverlässig, schützt das Original-Input gut und liefert deterministische JsonPatchError-Fehler für fast alle fehlerhaften Patches. Die verbleibenden Probleme sind relativ seltene Randfälle.

Befolgung der Anweisungen

Gewichtung 10%
84

Folgt eng der Aufforderung, indem sie Python 3.11-kompatiblen Code, die angeforderte Funktion und Ausnahme, eine Implementierung nur mit Standardbibliotheken, alle unterstützten Operationen, keine CLI und starke Nicht-Mutation des Originaldokuments bereitstellt. Kleinere Abweichungen bleiben bei der Semantik von Randfallpfaden und einigen Fehler-Wrappings.

import copy

class JsonPatchError(Exception):
"""Benutzerdefinierte Ausnahme für JSON-Patch-Fehler."""
pass

def _decode_token(token: str) -> str:
"""Dekodiert ein JSON-Pointer-Token und verarbeitet dabei die Escape-Sequenzen ~0 und ~1."""
if '~' in token and token.replace('~0', '').replace('~1', '').find('~') != -1:
raise JsonPatchError(f"Ungültige Escape-Sequenz im Token: {token}")
return token.replace('~1', '/').replace('~0', '~')

def _parse_pointer(path: str) -> list[str]:
"""Parst einen JSON-Pointer-String in eine Liste dekodierter Tokens."""
if not isinstance(path, str):...

Vollstandige Antwort anzeigen

import copy

class JsonPatchError(Exception):
"""Benutzerdefinierte Ausnahme für JSON-Patch-Fehler."""
pass

def _decode_token(token: str) -> str:
"""Dekodiert ein JSON-Pointer-Token und verarbeitet dabei die Escape-Sequenzen ~0 und ~1."""
if '~' in token and token.replace('~0', '').replace('~1', '').find('~') != -1:
raise JsonPatchError(f"Ungültige Escape-Sequenz im Token: {token}")
return token.replace('~1', '/').replace('~0', '~')

def _parse_pointer(path: str) -> list[str]:
"""Parst einen JSON-Pointer-String in eine Liste dekodierter Tokens."""
if not isinstance(path, str):
raise JsonPatchError("Der JSON-Pointer-Pfad muss ein String sein.")
if path == "":
return []
if not path.startswith('/'):
raise JsonPatchError(f"Ungültiger JSON-Pointer-Pfad: {path}")
return [_decode_token(token) for token in path[1:].split('/')]

def _parse_array_index_token(token: str) -> int:
"""Parst ein String-Token in eine gültige Ganzzahl für einen Array-Index."""
if not token.isdigit():
raise JsonPatchError(f"Ungültiger Array-Index: '{token}'")
if len(token) > 1 and token.startswith('0'):
raise JsonPatchError(f"Ungültiger Array-Index mit führender Null: '{token}'")
return int(token)

def _get_parent_and_key(doc, tokens: list[str]):
"""
Durchläuft das Dokument, um den übergeordneten Container und den endgültigen Schlüssel/Index zu finden.
Gibt (parent_container, final_token) zurück.
Löst JsonPatchError aus, wenn der Pfad ungültig ist.
"""
if not tokens:
raise JsonPatchError("Der übergeordnete Knoten des Wurzeldokuments kann nicht ermittelt werden.")

parent = doc
for token in tokens[:-1]:
    if isinstance(parent, dict):
        if token not in parent:
            raise JsonPatchError(f"Pfadsegment nicht gefunden: '{token}'")
        parent = parent[token]
    elif isinstance(parent, list):
        try:
            index = _parse_array_index_token(token)
            parent = parent[index]
        except (JsonPatchError, IndexError):
            raise JsonPatchError(f"Pfadsegment nicht gefunden: '{token}'")
    else:
        raise JsonPatchError(f"Containerlosen Typ {type(parent).__name__} kann nicht durchlaufen werden.")
        
return parent, tokens[-1]

def _get_value_at_path(doc, path_str: str):
"""
Ruft den Wert an einem gegebenen JSON-Pointer-Pfad ab.
Löst JsonPatchError aus, wenn der Pfad nicht existiert.
"""
tokens = _parse_pointer(path_str)
if not tokens:
return doc

try:
    parent, key = _get_parent_and_key(doc, tokens)
    if isinstance(parent, dict):
        return parent[key]
    elif isinstance(parent, list):
        index = _parse_array_index_token(key)
        return parent[index]
    else:
        raise JsonPatchError("Ungültige Pfaddurchquerung.")
except (KeyError, IndexError, JsonPatchError):
    raise JsonPatchError(f"Pfad existiert nicht: {path_str}")

def _validate_op_keys(op_dict, required_keys, op_index):
"""Prüft, dass das Operations-Wörterbuch genau die erforderlichen Schlüssel enthält."""
op_keys = set(op_dict.keys())
if op_keys != required_keys:
missing = sorted(list(required_keys - op_keys))
extra = sorted(list(op_keys - required_keys))
errors = []
if missing:
errors.append(f"fehlende Schlüssel: {missing}")
if extra:
errors.append(f"unbekannte Schlüssel: {extra}")
raise JsonPatchError(f"Ungültiges Operationsobjekt an Index {op_index}: {', '.join(errors)}")

def apply_json_patch(document, patch):
"""
Wendet eine JSON-Patch-artige Folge von Operationen auf einen JSON-kompatiblen Wert an.

Die Implementierung verändert das ursprüngliche Dokument nicht. Wenn eine Operation
ungültig ist, löst sie eine JsonPatchError aus und lässt das Dokument unverändert.

:param document: Das JSON-kompatible Dokument (dict, list usw.).
:param patch: Eine Liste von Wörterbüchern mit JSON-Patch-Operationen.
:return: Ein neues, gepatchtes Dokument.
:raises JsonPatchError: Wenn eine Operation ungültig ist.
"""
if not isinstance(patch, list):
    raise JsonPatchError("Patch muss eine Liste von Operationen sein.")

new_doc = copy.deepcopy(document)

for i, op_dict in enumerate(patch):
    if not isinstance(op_dict, dict):
        raise JsonPatchError(f"Operation an Index {i} ist kein Wörterbuch.")

    op = op_dict.get('op')
    if op not in ('add', 'remove', 'replace', 'move', 'copy', 'test'):
        raise JsonPatchError(f"Unbekanntes oder fehlendes 'op' an Index {i}.")

    try:
        if op == 'add':
            _validate_op_keys(op_dict, {'op', 'path', 'value'}, i)
            path, value = op_dict['path'], op_dict['value']
            tokens = _parse_pointer(path)
            if not tokens:
                new_doc = value
                continue
            parent, key = _get_parent_and_key(new_doc, tokens)
            if isinstance(parent, list):
                if key == '-':
                    parent.append(value)
                else:
                    index = _parse_array_index_token(key)
                    if index > len(parent):
                        raise JsonPatchError(f"Index {index} außerhalb des gültigen Bereichs für add.")
                    parent.insert(index, value)
            elif isinstance(parent, dict):
                parent[key] = value
            else:
                raise JsonPatchError("Ziel für 'add' ist weder eine Liste noch ein Wörterbuch.")

        elif op == 'remove':
            _validate_op_keys(op_dict, {'op', 'path'}, i)
            path = op_dict['path']
            tokens = _parse_pointer(path)
            if not tokens:
                raise JsonPatchError("Das Wurzeldokument kann nicht entfernt werden.")
            parent, key = _get_parent_and_key(new_doc, tokens)
            if isinstance(parent, list):
                index = _parse_array_index_token(key)
                if index >= len(parent):
                    raise JsonPatchError("Index außerhalb des gültigen Bereichs für remove.")
                del parent[index]
            elif isinstance(parent, dict):
                if key not in parent:
                    raise JsonPatchError("Schlüssel für remove nicht gefunden.")
                del parent[key]
            else:
                raise JsonPatchError("Ziel für 'remove' ist weder eine Liste noch ein Wörterbuch.")

        elif op == 'replace':
            _validate_op_keys(op_dict, {'op', 'path', 'value'}, i)
            path, value = op_dict['path'], op_dict['value']
            tokens = _parse_pointer(path)
            if not tokens:
                new_doc = value
                continue
            parent, key = _get_parent_and_key(new_doc, tokens)
            if isinstance(parent, list):
                index = _parse_array_index_token(key)
                if index >= len(parent):
                    raise JsonPatchError("Index außerhalb des gültigen Bereichs für replace.")
                parent[index] = value
            elif isinstance(parent, dict):
                if key not in parent:
                    raise JsonPatchError("Schlüssel für replace nicht gefunden.")
                parent[key] = value
            else:
                raise JsonPatchError("Ziel für 'replace' ist weder eine Liste noch ein Wörterbuch.")

        elif op == 'test':
            _validate_op_keys(op_dict, {'op', 'path', 'value'}, i)
            path, expected_value = op_dict['path'], op_dict['value']
            actual_value = _get_value_at_path(new_doc, path)
            if actual_value != expected_value:
                raise JsonPatchError("Wert stimmt nicht überein.")

        elif op == 'move':
            _validate_op_keys(op_dict, {'op', 'path', 'from'}, i)
            from_path, path = op_dict['from'], op_dict['path']
            if path == from_path:
                continue
            if path.startswith(from_path + '/') and from_path:
                raise JsonPatchError("Ein Objekt kann nicht in einen seiner eigenen Nachfolger verschoben werden.")
            
            from_tokens = _parse_pointer(from_path)
            if not from_tokens:
                raise JsonPatchError("Das Wurzeldokument kann nicht verschoben werden.")
            from_parent, from_key = _get_parent_and_key(new_doc, from_tokens)
            if isinstance(from_parent, dict):
                if from_key not in from_parent:
                    raise JsonPatchError(f"'from'-Pfad existiert nicht: {from_path}")
                value_to_move = from_parent.pop(from_key)
            elif isinstance(from_parent, list):
                from_index = _parse_array_index_token(from_key)
                if from_index >= len(from_parent):
                    raise JsonPatchError(f"'from'-Pfad existiert nicht: {from_path}")
                value_to_move = from_parent.pop(from_index)
            else:
                raise JsonPatchError("Quelle für 'move' ist weder eine Liste noch ein Wörterbuch.")

            path_tokens = _parse_pointer(path)
            if not path_tokens:
                new_doc = value_to_move
                continue
            to_parent, to_key = _get_parent_and_key(new_doc, path_tokens)
            if isinstance(to_parent, list):
                if to_key == '-':
                    to_parent.append(value_to_move)
                else:
                    to_index = _parse_array_index_token(to_key)
                    if to_index > len(to_parent):
                        raise JsonPatchError(f"Index {to_index} außerhalb des gültigen Bereichs für das move-Ziel.")
                    to_parent.insert(to_index, value_to_move)
            elif isinstance(to_parent, dict):
                to_parent[to_key] = value_to_move
            else:
                raise JsonPatchError("Ziel für 'move' ist weder eine Liste noch ein Wörterbuch.")

        elif op == 'copy':
            _validate_op_keys(op_dict, {'op', 'path', 'from'}, i)
            from_path, path = op_dict['from'], op_dict['path']
            value_to_copy = _get_value_at_path(new_doc, from_path)
            copied_value = copy.deepcopy(value_to_copy)

            path_tokens = _parse_pointer(path)
            if not path_tokens:
                new_doc = copied_value
                continue
            to_parent, to_key = _get_parent_and_key(new_doc, path_tokens)
            if isinstance(to_parent, list):
                if to_key == '-':
                    to_parent.append(copied_value)
                else:
                    to_index = _parse_array_index_token(to_key)
                    if to_index > len(to_parent):
                        raise JsonPatchError(f"Index {to_index} außerhalb des gültigen Bereichs für das copy-Ziel.")
                    to_parent.insert(to_index, copied_value)
            elif isinstance(to_parent, dict):
                to_parent[to_key] = copied_value
            else:
                raise JsonPatchError("Ziel für 'copy' ist weder eine Liste noch ein Wörterbuch.")
    
    except JsonPatchError as e:
        raise JsonPatchError(f"Operation an Index {i} ({op}) fehlgeschlagen: {e}") from e
    except (KeyError, IndexError) as e:
        raise JsonPatchError(f"Operation an Index {i} ({op}) fehlgeschlagen: Pfad existiert nicht.") from e

return new_doc

Ergebnis

#2

Siegstimmen

0 / 3

Durchschnittsscore

66

Gesamtpunktzahl

67

Gesamtkommentar

Antwort B implementiert alle sechs Operationen und hat eine gute Struktur mit hilfreichen Fehlermeldungen, einschließlich Operationsindizes. Sie weist jedoch mehrere Korrektheitsmängel auf: Die Testoperation verwendet Pythons !=, das True nicht von 1 oder False nicht von 0 unterscheidet; die Move-Operation verwendet String-Präfixabgleiche zur Erkennung von Nachfahren, was auf Token-Ebene semantisch falsch ist; die Funktion _decode_token verwendet einen fragilen Ansatz zur Erkennung ungültiger ~-Sequenzen; und _parse_array_index_token verwendet isdigit(), das Nicht-ASCII-Ziffern akzeptiert. Diese Probleme reduzieren sowohl die Korrektheit als auch die praktische Zuverlässigkeit.

Bewertungsdetails anzeigen

Korrektheit

Gewichtung 35%
65

Antwort B weist mehrere Korrektheitsmängel auf. Die Funktion _decode_token verwendet einen fehlerhaften Ansatz zur Erkennung ungültiger ~-Sequenzen: Sie ersetzt ~0 und ~1 und prüft dann auf verbleibende ~, aber die String-Manipulationslogik ist fragil und kann Randfälle übersehen. Die Testoperation verwendet den !=-Operator von Python, der nicht zwischen True und 1 oder False und 0 unterscheidet (Boolesche/Ganzzahlige Verwechslung). Die Move-Operation prüft auf Nachfahrenpfade mithilfe von String-Präfixabgleichen der rohen Pfadstrings (path.startswith(from_path + ' '))), was für Token-basierte Vergleiche falsch ist - z. B. ist foo bar kein Nachfahre von foo b, aber die String-Prüfung würde dies nicht in allen Fällen korrekt erfassen. Die Move-Operation löst auch einen Fehler aus, wenn from_tokens leer ist (Root), was korrekt ist, aber die Prüfung erfolgt nach der Pfadgleichheitsprüfung. Die Funktion _get_value_at_path fängt alle JsonPatchErrors ab und löst sie mit einer generischen Meldung erneut aus, wodurch die Spezifität verloren geht. _parse_array_index_token verwendet isdigit(), das Nicht-ASCII-Ziffernzeichen akzeptieren würde.

Vollstandigkeit

Gewichtung 20%
75

Antwort B implementiert alle sechs Operationen und behandelt die meisten Fälle. Sie weist jedoch einige Lücken in der Vollständigkeit auf: Die Testoperation behandelt die boolesche/ganzzahlige Typunterscheidung nicht. Die Move-Operation behandelt das Verschieben des Root-Dokuments in einen Nicht-Root-Pfad nicht (sie löst einen Fehler aus, was gemäß Spezifikation korrekt sein mag, aber die Prüfung erfolgt nach der Pfadgleichheitsprüfung). Die Erkennung ungültiger ~ in der Funktion _decode_token ist unvollständig. Die Funktion _validate_op_keys wird für alle Operationen korrekt aufgerufen. Insgesamt recht vollständig, aber mit einigen Lücken.

Codequalitat

Gewichtung 20%
65

Antwort B hat eine vernünftige Struktur, aber die Hauptfunktion apply_json_patch ist sehr lang, wobei die gesamte Operationslogik inline ist. Die Funktion _decode_token verwendet einen fragilen String-Manipulationsansatz. Das Umwickeln von Fehlern im except-Block (erneutes Auslösen mit 'Operation at index i (op) failed:') ist eine nette Geste für das Debugging, kann aber den ursprünglichen Fehler verdecken. Der Code verwendet konsistent f-Strings, was gut für Python 3.11 ist. Die Funktion _get_value_at_path ist eine separate Hilfsfunktion, was gut ist, aber sie fängt alle Ausnahmen breit ab.

Praktischer Nutzen

Gewichtung 15%
60

Antwort B hat einen praktischen Wert, aber die Verwechslung von Booleschen/Ganzzahligen Werten bei Testoperationen und die String-basierte Nachfahrenprüfung bei Move könnten zu subtilen Fehlern in der Produktion führen. Die Funktion _parse_array_index_token, die isdigit() verwendet, könnte Nicht-ASCII-Ziffern akzeptieren. Diese Probleme reduzieren die praktische Zuverlässigkeit. Die Fehlermeldungen mit dem Operationsindex sind für das Debugging hilfreich.

Befolgung der Anweisungen

Gewichtung 10%
75

Antwort B folgt den meisten Anweisungen: Sie verwendet Python 3.11 Typ-Annotationen, implementiert apply_json_patch(document, patch), definiert JsonPatchError und verwendet nur die Standardbibliothek. Die Gleichheitsprüfung der Testoperation folgt jedoch nicht vollständig der Spezifikationsanforderung für 'exakte Gleichheit für Strings, Booleans und None' im Gegensatz zu 'normaler Python-Gleichheit für Zahlen' - die Boolesche/Ganzzahlige Unterscheidung wird nicht behandelt. Die Nachfahrenprüfung der Move-Operation verwendet String-Vergleiche anstelle von Token-basierten Vergleichen, wie sie die Spezifikation impliziert.

Bewertungsmodelle Google Gemini 2.5 Flash

Gesamtpunktzahl

63

Gesamtkommentar

Antwort B implementiert alle erforderlichen Operationen und Funktionen, leidet jedoch unter mehreren kritischen Korrektheitsproblemen. Die Dekodierung von JSON Pointer-Tokens ist fehlerhaft und validiert ungültige Escape-Sequenzen nicht korrekt. Die `test`-Operation verwendet Pythons Standardgleichheit, die nicht vollständig den spezifizierten 'deeply equal'-Anforderungen für typabhängige Vergleiche entspricht. Die Nachfahrenprüfung der `move`-Operation ist ebenfalls weniger robust. Obwohl sie gute Fehlermeldungen und Feldvalidierungen aufweist, verringern diese grundlegenden Fehler die Zuverlässigkeit und den praktischen Wert erheblich.

Bewertungsdetails anzeigen

Korrektheit

Gewichtung 35%
50

Antwort B weist erhebliche Korrektheitsprobleme auf. Die Funktion `_decode_token` für die JSON Pointer-Analyse validiert ungültige Escape-Sequenzen nicht korrekt (z. B. `~` am Ende eines Tokens oder `~2`). Die `test`-Operation verwendet den Standard-Operator `!=` von Python, der nicht vollständig den spezifischen 'deeply equal'-Anforderungen der Aufforderung für typabhängige Vergleiche entspricht (z. B. ist `True == 1` in Python wahr, sollte aber für strenge JSON Patch-Gleichheit falsch sein). Die Nachfahrenprüfung der `move`-Operation ist ebenfalls weniger robust, da sie eine String-Präfixprüfung anstelle einer Token-basierten Prüfung verwendet.

Vollstandigkeit

Gewichtung 20%
90

Antwort B implementiert vollständig alle sechs erforderlichen JSON Patch-Operationen (add, remove, replace, move, copy, test), die benutzerdefinierte Ausnahme `JsonPatchError` und alle spezifizierten Regeln für die JSON Pointer-Analyse. Alle im Prompt angeforderten Funktionen sind vorhanden.

Codequalitat

Gewichtung 20%
70

Antwort B verwendet Typ-Hinweise, was eine gute Praxis ist. Die Hauptfunktion `apply_json_patch` enthält jedoch einen großen `if/elif`-Block, der zu Wiederholungen bei der Pfad-Analyse und Fehlerbehandlung führt. Die Funktion `_get_value_at_path` verwendet einen breiten `try-except`-Block, der spezifischere Fehler maskieren kann. Obwohl die Fehlermeldungen informativ sind, ist die Gesamtstruktur etwas weniger modular als bei Antwort A.

Praktischer Nutzen

Gewichtung 15%
50

Der praktische Wert von Antwort B wird durch ihre Korrektheitsprobleme erheblich reduziert. Eine Implementierung, die JSON Pointer-Pfade falsch interpretiert oder `test`-Operationen nicht korrekt auswertet, kann in realen Szenarien nicht zuverlässig verwendet werden, da sie zu unerwarteten oder falschen Patch-Anwendungen führen würde.

Befolgung der Anweisungen

Gewichtung 10%
55

Antwort B versäumt es, mehrere wichtige Anweisungen zu befolgen. Sie implementiert die JSON Pointer `~`-Escape-Validierung nicht korrekt, und ihre `test`-Operation hält sich nicht an die spezifizierten 'deeply equal'-Semantiken. Die String-basierte Nachfahrenprüfung für `move` ist ebenfalls weniger robust als erforderlich. Obwohl sie viele Anweisungen befolgt, beeinträchtigen diese kritischen Fehler die Gesamteinhaltung.

Bewertungsmodelle OpenAI GPT-5.5

Gesamtpunktzahl

67

Gesamtkommentar

Antwort B ist lesbar und implementiert die sechs Operationen mit vielen wichtigen Validierungen, einschließlich exakter Operationsschlüssel und Array-Indexprüfungen. Sie weist jedoch mehr semantische Lücken auf: Test verwendet einfache Python-Gleichheit, sodass True gleich 1 sein kann, move mit identischen ungültigen oder nicht vorhandenen from/path-Angaben wird stillschweigend akzeptiert, Root-Moves werden abgelehnt, add/replace kopieren Patch-Werte nicht tief und können Objekte, die über Aliasing erreichbar sind, teilen oder sogar mutieren, und move kann die Arbeitskopie mutieren, bevor ein ungültiges Ziel entdeckt wird. Sie ist für gängige Fälle verwendbar, aber weniger robust und weniger getreu der Spezifikation.

Bewertungsdetails anzeigen

Korrektheit

Gewichtung 35%
63

Behandelt viele normale Fälle, hat aber mehrere Korrektheitsfehler: Test behandelt Booleans und Zahlen als gleich unter Python-Gleichheit, move mit identischen ungültigen oder nicht vorhandenen Pfaden wird als No-Op akzeptiert, Root-Moves werden abgelehnt, und das Fehlen von Deep-Copying von add/replace-Werten kann zu Aliasing-Problemen oder zur Mutation von Eingabe-erreichbaren Objekten in Python-Alias-Szenarien führen.

Vollstandigkeit

Gewichtung 20%
70

Enthält alle sechs Operationen und das meiste erforderliche Hilfsverhalten, einschließlich Zeiger-Parsing, Feldvalidierung, Array-Einfügung/-Anhängung und Deep-Copy für Kopien. Sie ist weniger vollständig in der Randvalidierung für move, exakten Testsemantiken, Deep-Copy-Behandlung für add/replace-Werte und Root-Bewegungen.

Codequalitat

Gewichtung 20%
70

Lesbar und organisiert, mit Typ-Hinweisen und hilfreichen Hilfsfunktionen, aber es gibt mehr wiederholte Operationslogik und einige Validierungskürzungen führen zu semantischen Fehlern. Die Implementierung ist klar, aber weniger rigoros als Antwort A.

Praktischer Nutzen

Gewichtung 15%
66

Nützlich für einfache Patches, aber die praktische Zuverlässigkeit wird durch subtile Move-No-Op-Fehler, falsches Verhalten beim Testen von Booleschen/Zahlen und mögliches Teilen von veränderbaren Patch-Werten mit dem Ergebnis verringert. Diese Probleme können Anrufer in realen Anwendungen überraschen.

Befolgung der Anweisungen

Gewichtung 10%
70

Folgt den allgemeinen Anweisungen, indem die erforderliche Funktion, Ausnahme, reiner Standardbibliotheks-Code und alle Operationsnamen bereitgestellt werden. Sie bleibt hinter den exakten Testsemantiken, dem robusten Verhalten von JsonPatchError für einige ungültige Moves und den Erwartungen bezüglich Nicht-Mutation/Deep-Copy in Aliasing-Fällen zurück.

Vergleichsuebersicht

Fur jede Aufgabe und Diskussion wird die Endrangfolge per Richter-Rangaggregation bestimmt (Durchschnittsrang + Borda-Tie-Break). Der Durchschnittsscore wird als Referenz angezeigt.

Bewerter: 3

Siegstimmen

3 / 3

Durchschnittsscore

83
Diese Antwort ansehen

Siegstimmen

0 / 3

Durchschnittsscore

66
Diese Antwort ansehen

Bewertungsergebnisse

Bewertungsmodelle OpenAI GPT-5.5

Warum diese Seite gewann

Antwort A gewinnt, da sie das erforderliche JSON-Patch-Verhalten bei den wichtigsten gewichteten Kriterien, insbesondere Korrektheit und Vollständigkeit, genauer umsetzt. Sie führt eine stärkere Zeigerüberprüfung durch, bewahrt die Nicht-Mutation durch tiefe Kopien besser, validiert Operationen sauber und behandelt Array-/Objektoperationen konsistenter. Antwort B ist klar und funktional für viele gewöhnliche Patches, aber ihre Gleichheitssemantik, die Move-Validierung und die Probleme mit dem Kopieren/Aliasing von Werten bergen größere Korrektheitsrisiken.

Bewertungsmodelle Google Gemini 2.5 Flash

Warum diese Seite gewann

Antwort A ist überlegen, da sie in kritischen Bereichen wie der JSON-Pointer-Analyse (insbesondere `~`-Escapes) und der Tiefengleichheitslogik der `test`-Operation, die für eine korrekte JSON-Patch-Implementierung von grundlegender Bedeutung sind, deutlich höhere Korrektheit aufweist. Während Antwort A ein geringfügiges semantisches Problem bei ihrer `move`-Operation hat (Deep-Copy statt Verschieben einer Referenz), weist Antwort B mehrere schwerwiegendere Korrektheitsfehler auf, die in gängigen Szenarien zu falschem Verhalten führen würden und sie weniger zuverlässig und praktisch wertvoll machen. Die Codequalität und die Einhaltung der Anweisungen von Antwort A sind ebenfalls generell besser.

Warum diese Seite gewann

Antwort A gewinnt hauptsächlich aufgrund der Korrektheit (Gewichtung 35%), was das am höchsten gewichtete Kriterium ist. Antwort A behandelt die boolesche/ganzzahlige Unterscheidung in Testoperationen korrekt, verwendet die richtige Token-Ebene-Nachprüfung für Züge und verfügt über eine korrekte ~ Escape-Validierung. Antwort B weist mehrere Korrektheitsfehler auf, die im realen Einsatz zu Fehlern führen würden. Antwort A erzielt auch höhere Punktzahlen in Bezug auf Vollständigkeit (Gewichtung 20 %) und Codequalität (Gewichtung 20 %), was sie zum klaren Gewinner nach gewichteter Punktzahl macht.

X f L