Normalisierung in Representern


Damit Lösungen mit unwesentlichen Unterschieden dieselbe Repräsentation erhalten, sollte der Representer Normalisierungen anwenden. Im Allgemeinen sieht der Prozess, eine normalisierte Repräsentation zu erstellen, so aus:

  • Den Code der Lösung in einen abstrakten Syntaxbaum (AST) parsen
  • Normalisierungen auf den AST anwenden
  • Den normalisierten AST in einen String umwandeln
  • Den normalisierten AST-String in eine Datei namens representation.txt schreiben (siehe die Schnittstelle)

Beachte aber, dass die Repräsentation kein AST sein muss; es kann auch regulärer (normalisierter) Code sein, je nachdem, was für deinen Track am besten funktioniert.

Damit du loslegen kannst, stellen wir dir jetzt einige gängige Normalisierungsstrategien vor.

Hinweis 1: Die Normalisierungsbeispiele bauen nicht aufeinander auf, sie zeigen jeweils nur eine bestimmte Normalisierung. Ein echter Representer würde sie der Reihe nach anwenden.

Hinweis 2: Der Code in diesen Richtlinien ist in C#, aber die Richtlinien sind sprachunabhängig.

Bezeichner normalisieren

Damit Repräsentationen unabhängig von der Benennung sind, können benutzerdefinierte Namen (wie Variablen, Funktionen usw.) durch Platzhalter ersetzt werden. In diesem Fall sollte eine mapping.json erzeugt werden (siehe die Schnittstelle).

Wichtig ist, dass alle identischen Namen durch denselben Platzhalter ersetzt werden müssen, unabhängig vom Gültigkeitsbereich.

Quellcode

public static class Fake
{
    public static int Test(int input)
    {
        var test = input + 2;
        return test;
    }
}

Repräsentation

public static class PLACEHOLDER_1
{
    public static int PLACEHOLDER_2(int PLACEHOLDER_3)
    {
        var PLACEHOLDER_4 = PLACEHOLDER_3 + 2;
        return PLACEHOLDER_4;
    }
}

Whitespace normalisieren

Uneinheitlicher Whitespace kommt so häufig vor, dass seine Normalisierung ein üblicher Normalisierungsschritt ist. Auch Zeilenenden sollten normalisiert werden.

Quellcode

using   System;

     public static    class Fake
{
    public     static   DateTime Add    (DateTime    birthDate)
    {
        return birthDate.Add( TimeSpan.FromSeconds   (   10  ) )   ;
    }
}

Repräsentation

public static class Fake
{
    public static DateTime Add(DateTime birthDate)
    {
        return birthDate.Add(TimeSpan.FromSeconds(10));
    }
}

Blöcke normalisieren

In vielen Sprachen hat der Nutzer etwas Freiheit darin, wie er einen Block (oder Gültigkeitsbereich) definiert. In den meisten C-ähnlichen Sprachen wird der Gültigkeitsbereich zum Beispiel zwischen geschweiften Klammern deklariert. Normalerweise macht es keinen Unterschied, ob du sie in dieselbe Zeile oder in die nächste schreibst, also könnte man das normalisieren.

Quellcode

public static class Fake {
    public static int Test() {
        if (1 > 2) {
            return 0;
        }

        return 1;
    }
}

Repräsentation

public static class Fake
{
    public static int Test()
    {
        if (1 > 2)
        {
            return 0;
        }

        return 1;
    }
}

Unbedeutenden Code entfernen

Nicht jeder Teil des Codes ist für den Representer von Bedeutung und kann deshalb entfernt werden. In den meisten Sprachen sind Kommentare zum Beispiel unbedeutend und können bedenkenlos entfernt werden.

Quellcode

/*
   These are some very nice
   comments spanning multiple lines
*/
public static class Fake
{
    // Nice method
    public static string Test()
    {
        return "Test"; // This is very nice
    }
}

Repräsentation

public static class Fake
{
    public static string Test()
    {
        return "Test";
    }
}

Die Reihenfolge normalisieren, wo sie unbedeutend ist

In manchen Fällen spielt die Reihenfolge des Codes keine Rolle. Damit derselbe Code in unterschiedlicher Reihenfolge nicht zu unterschiedlichen Repräsentationen führt, kann es sinnvoll sein, ihn zu sortieren. Meist sind die zu sortierenden Elemente Funktionen oder Deklarationen. Es kann knifflig sein, das oder die Sortierkriterium beziehungsweise die Sortierkriterien zu finden, und ebenso knifflig, sie umzusetzen. Ein Kriterium könnte sein, wie viele AST-Kindknoten der Knoten enthält, ein anderes der Name des Typs des ersten Kindknotens.

Dieses Beispiel sortiert nach einer Art Funktionslänge:

Quellcode

public static class Fake
{
    public static string Test2()
    {
        int a = "Test2";
        return a;
    }

    public static string Test()
    {
        return "Test";
    }
}

Repräsentation

public static class Fake
{
    public static string Test()
    {
        return "Test";
    }

    public static string Test2()
    {
        int a = "Test2";
        return a;
    }
}