Seite 1 von 2

regular expression Anfang

Verfasst: Freitag 16. August 2013, 09:24
von harald
Hi

Ich bin ein absoluter Neuling was Python angeht und versuche derzeit in einem file alle Zeilen zu finden die mit einen ; enden. Es soll sowohl mit den Zeilenumbruch von Windows als auch Linux umgehen können. Habe folgende Zeile versucht aber es geht nicht. Wenn ich (\r)? weglasse funktioniert es für Linux. Vielleicht könnt ihr mir einen Tipp geben wo der Fehler ist. Danke im vorhinein.

Code: Alles auswählen

re.search(r"([;](\r)?)$", line)
MFG Harald

Re: regular expression Anfang

Verfasst: Freitag 16. August 2013, 09:42
von Sirius3
Hi harald,

neben der Tatsache, dass die ganzen Klammern überflüssig sind, tut bei mir alles:

Code: Alles auswählen

>>> re.search(r";\r?$", "bla;\r\n")
<_sre.SRE_Match object at 0x1079cfd98>
>>> re.search(r";\r?$", "bla;\n")
<_sre.SRE_Match object at 0x1079cfe00>
Alternativ kannst Du auch nach ";\s*$" suchen, dann ist es egal, welche Art unsichtbarer Zeichen nach dem ";" kommen.

Re: regular expression Anfang

Verfasst: Freitag 16. August 2013, 09:47
von harald
OK danke. Und wenn ich nun Sätze finden will die nicht auf ; enden reicht es dann vorm ; ein ^ zu schreiben?

MFG Harald

Re: regular expression Anfang

Verfasst: Freitag 16. August 2013, 09:49
von BlackJack
Wobei sich das auch noch prima ohne kryptische reguläre Ausdrücke testen lässt:

Code: Alles auswählen

line.rstrip().endswith(';')
@harald: Nein, dazu muss das ';' auch noch mit dem '^' in eckigen Klammern stehen, denn nur dort hat es die Bedeutung die Du haben möchtest. Ohne regulären Ausdruck:

Code: Alles auswählen

not line.rstrip().endswith(';')

Re: regular expression Anfang

Verfasst: Freitag 16. August 2013, 10:00
von harald
Also abgesehen von den Klammer müsste der folgende code funktionieren oder? Bei mir funktioniert er leider nicht. Zu den alternativen muss ich sagen das ich re verwenden muss.

Code: Alles auswählen

re.search(r"([^;](\r)?)$", line)
MFG Harald

Re: regular expression Anfang

Verfasst: Freitag 16. August 2013, 10:15
von Sirius3
Kannst Du ein Beispiel zeigen?

Re: regular expression Anfang

Verfasst: Freitag 16. August 2013, 11:23
von harald
Habe folgendes Testfile:

Code: Alles auswählen

int test();

int test(int i)
{

}

void main()
{

  int i = 0;
  char text[50];

  LOG();

}
Mit folgenden code möchte ich die richtigen Zeilen findet.

Code: Alles auswählen

        for line in findFile:
            if re.search(r"([^;](\r)?)$",line):
                print line
Er gibt mir immer die Zeile int test(); auch aus obwohl er diese weglassen sollte.

mfg Harald

Re: regular expression Anfang

Verfasst: Freitag 16. August 2013, 11:41
von Sirius3
Hallo harald,
so kannst Du Deinen regulären Ausdruck ja auch nicht negieren. Es wird natürlich immer ein Zeichen gefunden das nicht ";" ist (nämlich das Zeilenendezeichen). Wenn Du C-Code analysieren willst, sind reguläre Ausdrücke schwierig und das zeilenbasiert zu tun fehlerhaft, da C nicht zeilenbasiert ist.

Re: regular expression Anfang

Verfasst: Freitag 16. August 2013, 11:46
von BlackJack
@harald: Du hast da ja zum Beispiel ' LOG();\n'. Und da matched Dein regulärer Ausdruck natürlich. Das '[^;]' passt auf das Zeilenendezeichen und das '\r?' passt auf die leere Zeichenkette die danach kommt. Das ist gar nicht so einfach, insbesondere wenn in der letzten Zeile zum Beispiel kein Newline oder Carriage Return Zeichen am Ende steht. Schönes Beispiel wo reguläre Ausdrücke keine gute Idee sind, weil man das mit den anderen Methoden auf Zeichenketten viel einfacher und verständlicher ausdrücken kann.

Re: regular expression Anfang

Verfasst: Montag 19. August 2013, 15:16
von harald
So bin jetzt gerade dabei einen fertigen C Parser zu suchen welcher mir es ermöglicht bestimmte Befehle im Code zu finden und dort dann auch sagen zu können in welcher Funktion die Funktion steht bzw in welcher Zeile im Source Code. Bin jetzt mal auf den pycparser gestoßen. Gibt es von euch nocht Vorschläge für andere Parser oder eine Idee wie ich meine Aufgabe sonst lösen könnte? Mit regular expressions ist es das Problem das ich nicht immer sagen kann das der c Code gleich ausschaut.

mfg Harald

Re: regular expression Anfang

Verfasst: Montag 19. August 2013, 15:24
von snafu
Was sollen denn "bestimmte Befehle" genau sein? Geht es um Funktionsaufrufe, um Schlüsselwörter oder wie? Beschreibe doch mal dien eigentliches Ziel. Das bringt sicherlich mehr, als wenn du hier (gefühlt) mit jedem Beitrag deine Anforderungen änderst.

Re: regular expression Anfang

Verfasst: Montag 19. August 2013, 15:30
von harald
Ich muss bestimmte Funktionsaufrufe im Code erkennen und umschreiben. Meine derzeitige Idee wäre das ich mit Regular Expressions erkenne wo eine Funktion beginnt und wie diese heist. Danach suche ich innerhalb der Funktion wo ein von mir gesuchter Funktionsaufruf ist. Weitere Informationen über die zum Beispiel übergeben Variablen (welcher Typ?) an den Funktionsaufruf erhalte ich dann aus dem AST der vom Parser kommt.

mfg Harald

Re: regular expression Anfang

Verfasst: Montag 19. August 2013, 15:45
von snafu
Na, das hört sich doch tatsächlich so an, als wenn der bereits von dir erwähnte `pycparser` hier gut zum Einsatz kommen kann. Das würde dir schonmal den hässlichen Teil des Parsens ersparen. Du musst dich dann sicherlich noch ein bißchen durch den vom Parser erzeugten AST wuseln, um die von dir gewünschte Funktionalität zu erhalten, aber das müsstest du ja so oder so.

Du kannst halt nicht einfach einen regulären Ausdruck schreiben, bei dem du annimmst, dass eine Funktion immer nach dem Schema "Text, runde Klammer auf, ggf Text, runde Klammer zu, geschweifte Klammer auf, Text, geschweifte Klammer zu" oder so ähnlich aufgebaut ist. Das scheitert bereits daran, dass in C-Funktionen regelmäßig weitere geschweifte Klammernpaare geöffnet werden. Da würde ein naiv geschriebener regulärer Ausdruck beim Schließen eines inneren Klammernpaares sofort denken, es wäre das Funktionsende, weil er ja auf eine geschlossene geschweifte Klammer gestoßen ist. Du müsstest das daher im gesamten Kontext betrachten und quasi die Klammernpaare mitzählen. Allein dieser Umstand geht bereits über die Möglichkeiten von regulären Ausdrücken hinaus.

Wie gesagt: Lass dir diesen Teil der Arbeit von nem Tool abnehmen. Dann hast du wenigstens mit recht hoher Wahrscheinlichkeit einen korrekten AST und kannst dich auf dein eigentliches Ziel konzentrieren. ;)

EDIT: Ich empfehle übrigens einen Blick in die FAQs vom `pycparser`. Da steht zum Beispiel, dass es möglich ist, einen AST automatisch wieder in Code umwandeln zu lassen. Modifikationen und die anschließende Ausgabe des angepassten C-Codes dürften daher möglich sein. Einziges Manko: Der neu erzeugte Code wird höchstwahrscheinlich nicht mehr dieselbe Formatierung haben wie das Original (falls das eine Rolle spielt).

EDIT2: Und mit func_calls.py gibt es dort sogar ein Beispiel, wie man bestimmte Funktionsaufrufe nachverfolgen kann. Entspricht dies nicht in etwa deinem Vorhaben? Wäre zumindest ein Anfang. Achja, und in func_defs.py wird gezeigt, wie man Funktionsdefinitionen herausfischen kann.

Re: regular expression Anfang

Verfasst: Donnerstag 22. August 2013, 18:05
von harald
Hi
Also der pycparser funktioniert super und ich kann auch schon meine gesuchten Informationen ablesen. Habe alles mal mit einen Testfile probiert und dabei habe ich aber schon folgendes Problem. Die Testdatei benötigt types.h. Ich verwende die Fake Headers welche im Ordner Utils drinnen sind. Dort sind alle Headers drinnen außer types.h welche im Unterordner sys ist. Wenn ich die Datei in den Hauptordner kopiere funktioniert alles aber wenn ich sie nur im Unterordner habe geht es nicht. Der Aufruf des Parsers ist im folgenden zu sehen. Ich bringe den cpp aber nicht dazu das er im Ordner fake_libc_include recursive sucht und den Unterordner sys mitnimmt. Vielleicht kennt ja jemand eine Lösung für das Problem? Das kopieren oder verschieben von types.h ist leider keine Lösung da ich dann im Projekt selber auch die Header Dateien in unterschiedlichen Ordnern habe.

Code: Alles auswählen

ast = parse_file(totalFilePath, use_cpp=True, cpp_args=r'-Ipycparser-master/utils/fake_libc_include/')
mfg Harald

Re: regular expression Anfang

Verfasst: Donnerstag 22. August 2013, 18:55
von Sirius3
Hi,
C sucht nicht rekursiv nach Header-Dateien, also ist das Verhalten von pycparser hier gleich. Du mußt eben alle Pfade, die Du brauchst, mit -I angeben.

Re: regular expression Anfang

Verfasst: Donnerstag 29. August 2013, 13:30
von harald
Hi

Ok habe nun herausgefunden wie man mehrere Pfade angeben kann (mit []). Ich lasse mir nun alls Pfade heraussuchen wo header dateien enthalten sind und stelle einen String zusammen der passen sollte. Wenn ich den String an die Parse Funktion übergebe funktioniert es nicht wenn ich den Inhalt des String ausgebe und diesen in die python Datei kopiere dann gehts.

Code: Alles auswählen

self.headers = "[r'-Ipycparser-master/utils/fake_libc_include/', r'-Ipycparser-master/utils/fake_libc_include/sys/']"

# Funktioniert
ast = parse_file(filePath, use_cpp=True, cpp_args=[r'-Ipycparser-master/utils/fake_libc_include/', r'-Ipycparser-master/utils/fake_libc_include/sys/'])

# Funktioniert nicht
ast = parse_file(filePath, use_cpp=True, cpp_args='%s' %self.headers)

# Funktioniert nicht
ast = parse_file(filePath, use_cpp=True, cpp_args=self.headers)
Fehlermeldung:

Code: Alles auswählen

Datei 1 gefunden (/home/harald/Arbeitsfläche/Prototyp/helloWorld.c)
cpp: Fehler: r'-Ipycparser-master/utils/fake_libc_include/', r'-Ipycparser-master/utils/fake_libc_include/sys/': Datei oder Verzeichnis nicht gefunden
cpp: Warnung: »-x c« hinter letzter Eingabedatei hat keine Wirkung
cpp: schwerwiegender Fehler: keine Eingabedateien
Kompilierung beendet.

mfg Harald

Re: regular expression Anfang

Verfasst: Donnerstag 29. August 2013, 21:17
von Sirius3
der Name des Parameters (»cmd_args«) suggeriert ja schon, dass eine Liste mit Argumenten erwartet wird. Weder Fall 2 noch Fall 3 übergeben allerdings eine Liste. Auch wäre mir keine Funktion bekannt, die mit der Repräsentation einer Liste etwas sinnvolles anfangen kann (Außer vielleicht »eval« :P ).
Um es deutlicher zu sagen. In »self.headers« steht Quatsch drin, schau Dir einfach mal den Typ dieser Variable an.

Re: regular expression Anfang

Verfasst: Donnerstag 29. August 2013, 22:09
von harald
Hi
Also ich hätte eigentlich gedacht das wenn ich die zweite Variante nehme das er dann einfach den String der in self.headers drinnen steht dort hinschreibt und die Funktion ihn dann rictig interpretiert. Wenn ich nun aber eine Liste mache und jeden Pfad in diese Liste einfüge dann sollte es doch gehen oder?

mfg Harald

Re: regular expression Anfang

Verfasst: Donnerstag 29. August 2013, 22:14
von EyDu
harald hat geschrieben:Also ich hätte eigentlich gedacht das wenn ich die zweite Variante nehme das er dann einfach den String der in self.headers drinnen steht dort hinschreibt und die Funktion ihn dann rictig interpretiert.
Das wäre ein unglaublich schlechtes Verhalten. Dann müsste der Interpreter irgendwie entscheiden, welche Variante er denn nun gerade in diesem konkreten Fall wählen sollte.
harald hat geschrieben:Wenn ich nun aber eine Liste mache und jeden Pfad in diese Liste einfüge dann sollte es doch gehen oder?
Das schöne ist ja, dass man solche Sachen einfach ausprobieren kann und daraus lernt ;-)

Re: regular expression Anfang

Verfasst: Mittwoch 11. September 2013, 08:32
von harald
Hi
So ich bin nun schon relativ Weit mit den Parser und kann auch schon meine Funktionen erkennen. Nun dachte ich mir eigentlich das ich in einer Datei an eine bestimmte Zeile springen kann und dort die vorhandene Zeile mit einer neuen (die länger oder kürzer ist) ersetzen kann. Allerdings geht das anscheinend doch nicht und so habe ich gelesen das ich eine temporäre Datei erstellen muss in die ich den neuen Code reinschreibe und die dann umbennene zum Beispiel. Ich hoffe ich ihre mich nicht was das angeht den eigentlich würde ich lieber nur in der aktuellen Datei die Zeile ersetzen. Sollte das doch gehen bitte um Antwort.

Nun habe ich also zwei Ansätze:

1) Die alte Datei Zeilenweise in eine neue kopieren und die jeweiligen Zeilen einfach ersetzen. Danach die alte datei löschen und die neue umbenennen.

2) Die datei mit readlines() einlesen und in eine Liste Spiechern. In der Liste die jeweiligen Zeilen ändern und danach mit writelines() die liste wieder rausschreiben.

Nachdem vermutlich beide Varianten funktionieren habe ich mir überlegt das für mich die zweite Variante leichter zu implementieren wäre aber da ich dann eine Liste brauche die den kompletten Inhalt der Datei speichert ist die Frage welche der beiden Varianten besser ist in Bezug auf Performance?! Vielleicht habt ihr ja einen Rat dazu?

mfg Harald