Seite 1 von 1

Text Transformation Language

Verfasst: 22.09.2012, 14:43
von BeRsErKeR
Ich brauche auf der Arbeit oft Scripts und Tools für Textersetzungen und Umbenennung von Dateien. Meist reicht dafür ein Regex.Replace nicht aus und so habe ich angefangen eine kleine Text Transformation Language zu basteln, mit der ich die meisten Aufgabenstellungen erschlagen kann.

1. Aufbau:

Um eine Text-Transformation durchzuführen wird ein Ausdruck verwendet der aus 1-11 Bereichen besteht. Bereiche werden durch eine Raute (#) getrennt:

Code: Alles auswählen

Bereich1#Bereich2#...#Bereich11
Der erste Bereich ist der Ergebnisbereich, die anderen Bereiche sind Hilfsbereiche, die mit einer ID von 0-9 in allen Bereichen referenziert werden können. Der erste Bereich ist nicht referenzierbar. Das Resultat der Transformation befindet sich am Ende im Ergebnisbereich. Man kann sich dies in etwa wie einen Formatstring bei printf vorstellen, wobei weitere Bereiche dann Text-Parameter sind die im Formatstring eingefügt werden können. Allerdings sind alle Bereiche sozusagen Formatstrings. So kann beispielsweise der 2. Bereich ebenfalls andere Bereiche referenzieren. Zu beachten ist dabei, dass sich 2 Bereiche nicht gegenseitig referenzieren dürfen und das es keine Ring-Referenzierung gibt (z.B. Bereich 3 -> Bereich 4 -> Bereich 5 -> Bereich 3).

Jeder Bereich kann Text, Operatoren, Referenzen auf Bereiche und Variablen enthalten (siehe weiter unten).


2. Referenzierung von Bereichen:

Ein Bereich wird mit einem Dollarzeichen gefolgt von der Bereichs-ID referenziert. Z.B. $0, $1, usw. Da die ID immer einstellig ist referenziert $9 den letztmöglichen Bereich. Ist ein referenzierter Bereich nicht vorhanden, so wird dieser als leerer String interpretiert.

Beispiel:

Code: Alles auswählen

$0$1$2$9#Hallo# #Welt
// Ergebnis: "Hallo Welt"
Referenziert ein Bereich andere Bereich, so werden zunächst diese referenzierten Bereiche transformiert und anschließend eingefügt. Danach wird der Bereich selbst transformiert.


3. Operatoren:

Code: Alles auswählen

>	UpperCase (Wandelt den vorangegangen String in Großbuchstaben um)
<	LowerCase (Wandelt den vorangegangen String in Kleinbuchstaben um)
~	Reverse (Dreht die Reihenfolge der Zeichen um)
+	RepeatChar (Wiederholt das letzte Zeichen)
-	RemoveChar (Entfernt das letzte Zeichen)
()	Block (Markiert einen Block auf den sich der nachfolgende Operator bezieht, ansonsten wirken die meisten Operatoren auf den gesamten vorangegangen Text)
[i]	Index (Liefert das i-te Zeichen)
[i,l]	Substring (Liefert den Teilstring vom Index i an mit der Länge l)
	Ist i negativ so wird vom Ende ausgegangen: RealIndex = String.Length + i
	Ist l negativ so wird der Ergebnisstring umgedreht
	Fehlt l aber das Komma ist vorhanden, so handelt es sich um den Substring bis zum Ende (abc[1,] liefert "bc")
{n}	Repeat (Wiederholt den Text n mal)
{c,n}	RepeatRange (Wiederholt die letzten c Zeichen, n mal)
{"r"}	Regex (Wendet den regulären Ausdruck r an, das Match wird zurückgegeben)
\c	Escape (Liefert das Zeichen c ohne es zu interpretieren, z.B. \< ergibt das Zeichen '<')
Beispiele:

Code: Alles auswählen

Eingabe: test>
Ergebnis: TEST

Eingabe: foo[1]>
Ergebnis: O

Eingabe: Test123{"[0-9]+"}~
Ergebnis: 321

Eingabe: Go{1,4}gle
Ergebnis: Gooooogle

Eingabe: C\++
Ergebnis: C++

Eingabe: $0($1){2}#once#twice
Ergebnis: oncetwicetwice

4. Variablen

In der Regel möchte man nicht mit festen Strings arbeiten, da man dann keine Text-Transformation bräuchte. Daher können Variablen referenziert werden. Diese können Strings oder Zahlenwerte beinhalten. Sofern es sich um Zahlenwerte handelt können diese auch als Parameter für bestimmte Operatoren (z.B. Index, Substring, Repeat, usw verwendet werden).

Referenzen auf Variablen werden mit einem @ begonnen und beendet: @myvar@. In Parametern für Operatoren reicht der Variablenname ohne das @-Zeichen aus.

Ein Programm welches die TT-Sprache nutzt muss dem Interpreter/Transformator die Variablen mitgeben. Die Variablennamen selbst beinhalten nicht das @-Zeichen. Dies ist nur bei der Referenzierung nötig.

Beispiel:

Code: Alles auswählen

myvar1 = "foo"
myvar2 = 2

Eingabe: $0[myvar2,]#@myvar1@$1@myvar1@z#bar
Ergebnis: barfooz


Ich würde mich über Anmerkungen, Kritik und Ideen freuen.

Das Ziel ist beispielsweise ein Kommandozeilen-Tool ala awk, mit dem man auf einfache Weise Dateien umbenennen kann oder in Texten sehr einfach Inhalte ändern oder formatiert einfügen kann. Ich könnte mir auch vorstellen, dass man damit Dateininhalte formatiert anzeigen oder ausgeben lassen kann ohne jedesmal ein Programm zu schreiben.

Man könnte es aber auch als Regex-Alternative in Bibliotheken zur Verfügung stellen um bestimmte Textersetzungen zu ermöglichen.

Wer Lust hat kann ja rausfinden was der Ausdruck in meiner Signatur ergibt. ;)

Re: Text Transformation Language

Verfasst: 22.09.2012, 15:02
von BeRsErKeR
Noch ein paar Infos: Die Sprache ist so ausgelegt, dass sie von links nach rechts innerhalb der Bereiche ausgewertet wird. Ein Transformator soll möglichst schnell zum Ergebnis kommen. Verschachtelungen und ()-Blöcke wollte ich daher eigentlich vermeiden, aber ich glaub man wird sie brauchen. Ich stell mir aber vor, dass man die Ausdrücke recht schnell und einfach (ggf. eine gute Regex-Lib vorausgesetzt) transformieren kann. Ich hatte auch schonmal einen kleinen Transformator programmiert, aber ich werd nochmal einen neuen basteln.

Ich weiß aber nicht für wie sinnvoll ihr das ganze haltet und ob ihr vielleicht zu krasse Schwachstellen seht oder das ganze vielleicht zu umständlich und kryptisch empfindet. Wobei reguläre Ausdrücke das ja teilweise auch sind.

Was ich mir so vorstelle:

Code: Alles auswählen

dictionary<string, string> vars;
vars.add("var1", "foo");
vars.add("var2", "bar");
string result = transform("@var2@@var1@z>", vars);
// result = BARFOOZ
Oder:

Code: Alles auswählen

// Command shell
> echo transform -var=var1,foo -var=var2,bar "@var2@@var1@z>"
> BARFOOZ

Re: Text Transformation Language

Verfasst: 26.09.2012, 13:26
von BeRsErKeR
Hm irgendwie hät ich mir wenigstens mal 1 oder 2 Statements gewünscht und wenns nur "Wasn das fürn Käse?" gewesen wäre. :/

Re: Text Transformation Language

Verfasst: 26.09.2012, 13:35
von Schrompf
Wenn Du so explizit darum bittest: Regular Expressions finde ich schon furchtbar zu schreiben, und Deine Sprache vereint deren Komplexität mit dem zusätzlichen Ärgernis, eine neue Sprache mit genau 0 Verbreitung lernen zu müssen. Wenn Du das für Deine privaten Bedürfnisse machst, dann sei doch zufrieden damit, dass es Deine Probleme löst.

Re: Text Transformation Language

Verfasst: 26.09.2012, 14:01
von antisteo
sed und awk sind besser.

Re: Text Transformation Language

Verfasst: 26.09.2012, 14:34
von Sternmull
Irgendwie erschließt sich mir der Einsatzzweck nicht so richtig: Geht es um die Substitution innerhalb eines Strings (so wie in shellscripts und ini-files)? Oder um filter für text-streams (wie sed und awk)?

Ich persönlich verwende sed für einfache Umformatierungen. Für komplexere Sachen schreib ich mir ein paar Zeilen Python (z.b. Analyse von Logfiles usw.).

Re: Text Transformation Language

Verfasst: 28.09.2012, 16:18
von BeRsErKeR
antisteo hat geschrieben:sed und awk sind besser.
Naja besser schon, aber sie tun halt nicht genau das gleiche. sed kann zwar auch einiges, aber ich bin nicht nur auf Replacement aus, sondern auch auf Filterung, Konkatenation und Plattformunabhängigkeit (also jenseits von Shell-Scripten). Und awk kann auf jeden Fall mehr, aber es eignet sich mMn nicht dazu direkt in der Konsole (das Script in Textform meine ich damit) oder als Einzeiler im Programmcode als String verwendet zu werden. Und ich will halt keine Scriptsprache sondern eine Art Transformations-Ausdruck. Man könnte sagen einen Ausdruck, der auf regulären Ausdrücken aufsetzt aber für String-Manipulation gedacht ist. Regex ist ja eher für das Matchen von Strings gedacht und nicht für deren Manipulation.

Schrompf hat geschrieben:Wenn Du so explizit darum bittest: Regular Expressions finde ich schon furchtbar zu schreiben, und Deine Sprache vereint deren Komplexität mit dem zusätzlichen Ärgernis, eine neue Sprache mit genau 0 Verbreitung lernen zu müssen. Wenn Du das für Deine privaten Bedürfnisse machst, dann sei doch zufrieden damit, dass es Deine Probleme löst.
Hm ich finde reguläre Ausdrücke eigentlich recht einfach zu verstehen und zu schreiben, jedenfalls wenn man auf die ganzen neuen Konstrukte und Eigen-Erweiterungen verzichtet. Es kommt natürlich immer auf die Aufgabenstellung drauf an.

Sternmull hat geschrieben:Irgendwie erschließt sich mir der Einsatzzweck nicht so richtig: Geht es um die Substitution innerhalb eines Strings (so wie in shellscripts und ini-files)? Oder um filter für text-streams (wie sed und awk)?
Prinzipiell für beides. Beispiele sind:

- Dateien in einem Ordner auf eine bestimmte Weise umbenennen
- Dateiinhalte umwandeln
- Dateiendungen von Dateinamen ändern
- Stringkonkatenation
- Filtern bestimmter Daten aus Strings

Sternmull hat geschrieben:Ich persönlich verwende sed für einfache Umformatierungen. Für komplexere Sachen schreib ich mir ein paar Zeilen Python (z.b. Analyse von Logfiles usw.).
Gibts denn eine gute sed-Portierung für Windows? Ich würd das ganze halt gern plattformunabhängig haben, da ich teilweise gezwungen bin mit Windows zu arbeiten. Diese paar Zeilen Python stören mich gerade. Ich schreib halt auch für so einen Kleinkram immer neuen Code, obwohl es halt auch ohne ginge. Ob meine Sprache schon dafür ausreichend weiß ich nicht, aber ich bin ja auch noch nicht fertig.

Re: Text Transformation Language

Verfasst: 01.10.2012, 09:39
von BeRsErKeR
Ich habe nun das Konzept von Variablen entfernt. Stattdessen kann man nun direkt auf dem Input arbeiten (ähnlich wie bei sed). Dabei referenziert man den Input mit $$.

Beispielsweise wandelt folgender Ausdruck den Input in Großbuchstaben um und vertauscht die Reihenfolge der Zeichen:
Ich hab auch schon eine .NET-Library geschrieben, die Ausdrücke mit allen Operatoren transformieren kann. Das ganze ist auch auf Dateien (Zeile für Zeile) anwendbar. Der Transformator war so einfach zu realisieren, dass ich etwa in 4 Stunden fertig war.

Ich hab mir überlegt, dass man das ganze auch mit sed zusammen nutzen könnte.

Beispiel:

Code: Alles auswählen

s/[a-zA-Z0-9]+ /$$>/g
Damit würde man alle Wörter in einer Datei, die nur aus Buchstaben und Zahlen bestehen, in Großbuchstaben umwandeln.

Die Transformation scheint auch recht schnell zu gehen. Im Gegensatz zu regulären Ausdrücken können die hier genannten Ausdrücke (abgesehen davon wenn man den Regex-Operator nutzt) immer von links nach rechts ausgewertet werden. Die Transformation läuft also größtenteils linear ab. Subausdrücke (innerhalb von "()") werden ebenfalls linear transformiert und dann mit einem Marker in den Parent-Ausdruck eingefügt. Ein Operator nimmt als Ziel einfach den gesamten Text der schon im transformierten String steht oder einen Subausdruck, wenn dessen Endposition gleich der Länge des transformierten Strings ist.

Ich habe das ganze nun "Textra" genannt. Ich denke für kleinere Operationen ist das ganze durchaus brauchbar. Besonders so Standard-Texttransformationen wie LowerCase, UpperCase, Index, Substring und Reverse lassen sich sehr kurz ausdrücken.

Re: Text Transformation Language

Verfasst: 01.10.2012, 11:22
von antisteo
BeRsErKeR hat geschrieben:Gibts denn eine gute sed-Portierung für Windows? Ich würd das ganze halt gern plattformunabhängig haben, da ich teilweise gezwungen bin mit Windows zu arbeiten.
http://bit.ly/PFzfdJ

Aber ich glaube, du hast gar keine sed-Portierung nötig, da du wohl mehr Freude an der Entwicklung deiner eigenen Transformationssprache hast, als dir eine rasche Lösung des Problems bringen würde.

Re: Text Transformation Language

Verfasst: 01.10.2012, 14:40
von BeRsErKeR
Da ist was dran. Und die ursprüngliche Aufgabe war vorallem auf Änderungen von Groß-/Kleinschreibung und Konkenation ausgelegt und da find ich ein '>' bzw. '<' halt auch recht praktisch bzw. ich weiß gar nicht wie man das in sed recht kurz umsetzen könnte. Mittlerweile ist es aber wirklich so, dass mir das ganze Spaß macht und ich noch etwas Zeit hineinstecken möchte. Vielleicht noch ein paar Spielereien wie Operatoren für lastindexof oder firstindexof. Dann könnte man noch ein paar andere Dinge leicht umsetzen.

Zum Beispiel könnte ich mir folgendes vorstellen um Dateiendungen (hier zu png) zu ändern:

Code: Alles auswählen

$$[0,$.+1]png
Dabei wäre "$." der letzte Index des Zeichens '.'. "^." wäre dann z.B. der erste Index des Punkts.
Wobei das natürlich auch per Regex ginge, allerdings wirds da schwierig wenn der Dateiname selbst Punkte enthält.

Code: Alles auswählen

$${"[^\\/:*?\"<>|]+\.(?:[a-zA-Z0-9]+$)"}png
Keine Ahnung ob das klappen würde. Kann grad nicht testen. Ist auf jeden Fall unschön zu lesen und viel länger.