Oniguruma Wrapper [noch im Aufbau]

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Dienstag 25. September 2007, 22:28

Topic: Wrapper für die Regex-Engine Oniguruma 5.9.0

@birkenfeld: Danke für den Ausführlichen post. Wenn ich dich richtig verstanden habe, sollte der Wrapper eine Python C-Extension sein, der auf C ebene mit der Python API Oniguruma wrappt. Diese C-Extension muss mit VS 7 oder VS 8 kompiliert werden, damit die Extension unter Python 2.5@Win läuft. Anschließend wird die Extension über Python eingebunden das widerum die Extension Wrappt. Kurz (?): PyOnigurumaWrapper => PyOnigurumaC-Extension => libonig.a

Folgende Fragen dazu: Verstehe ich das richtig das ich für das kompilieren einer Python Extension den gleichen Kompiler verwenden muss mit dem `libpython25.a' kompiliert wurde, weil es sonst beim linken der Extension gegen die `libpython25.a' zu Problemen kommen kann (Daher die Empfehlung zu VS 7 oder VS 8 )?

Ich wollte das ganze eigentlich mit `ctypes` realisieren. Was spricht dagegen? Mein bisheriger Wrappcode (Eher Testcode) nutzt `ctypes`.

@blackbird: Schicke ich dir gerne zu, wenn es lauffähig ist und vom Status Testcode weck ist. Bisher beschränkt sich das ganze nur auf die definierung der Konstanten von `oniguruma.h' und der public API und ist nicht sonderlich schön strukturiert (Ist halt gechakter testcode). Mal sehen, wenn ich morgen zeitig zu Hause bin, schreibe ich's fertig und ne Abstraktion. Den Code könnte ich dir dann im laufe der Woche zusenden.

Um Unicode habe ich mir bisher keine Gedanken gemacht, das lässt sich aber sicherlich direkt über Python in eine für Oniguruma verständliche form transformieren.

Falls das mit `ctypes` keine so gute Idee ist, lasst es mich bitte wissen und auch mit Begründung.

Probleme:
Hab gestern onig unter Win gebacken gekriegt. Hab http://www.mingw.org/ und http://www.mingw.org/msys.shtml benutzt. Lief alles reibungslos (libonig.a einwandfrei, `make check' auf ohne Fehler) bis auf das erzeugen der DLL.

Konkret: `configure' == IO; `make' spuckt mir folgende Meldung aus:
libtool: link: warning: undefined symbols not allowed in i686-pc-mingw32 shared libraries
(Was mich auch ein wenig wunder ist, dass mein Sys als 686 erkannt wird und nicht als 386, hmm.)

OK, hab `make dll' gemacht und das spuckte mir ne dll aus. Hab aber gestern keine Zeit mehr gehabt um zu sehen ob es funktioniert, bin auch erst eben gerade wider zurück. Werd es morgen testen.

mfg

----
Weiterführung von diesem thread.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Mittwoch 26. September 2007, 19:12

poker hat geschrieben:Topic: Wrapper für die Regex-Engine Oniguruma 5.9.0

@birkenfeld: Danke für den Ausführlichen post. Wenn ich dich richtig verstanden habe, sollte der Wrapper eine Python C-Extension sein, der auf C ebene mit der Python API Oniguruma wrappt. Diese C-Extension muss mit VS 7 oder VS 8 kompiliert werden, damit die Extension unter Python 2.5@Win läuft. Anschließend wird die Extension über Python eingebunden das widerum die Extension Wrappt. Kurz (?): PyOnigurumaWrapper => PyOnigurumaC-Extension => libonig.a
Ja, wobei ein Python-Modul optional ist, wenn die C-Extension alle nötigen Funktionen und Klassen schon bereitstellt.
Ich wollte das ganze eigentlich mit `ctypes` realisieren. Was spricht dagegen? Mein bisheriger Wrappcode (Eher Testcode) nutzt `ctypes`.
Spricht eigentlich nichts dagegen, wenn das ctypes-Interface ausreicht. Dann sparst du dir natürlich, überhaupt C zu schreiben.
Um Unicode habe ich mir bisher keine Gedanken gemacht, das lässt sich aber sicherlich direkt über Python in eine für Oniguruma verständliche form transformieren.
Gerade das ist aber eine spannende Frage, da Python einmal intern zwei verschiedene Unicode-Formate verwendet (2 bzw. 4 bytes pro character) und das ganze natürlich auch einigermaßen schnell gehen sollte.
Gerade da ist auch die Frage, ob ctypes mitspielt.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Mittwoch 26. September 2007, 19:48

poker hat geschrieben:Ich wollte das ganze eigentlich mit `ctypes` realisieren. Was spricht dagegen? Mein bisheriger Wrappcode (Eher Testcode) nutzt `ctypes`.
Du dürftest Probleme haben die Structs nachzubasteln fürchte ich. Ich glaub das beste ist die onguruma Funktionen in C ein wenig wrappen und den Rest in Python erledigen. Aber gerade die Oniguruma Unicode Case Folding Sachen müssen vorher noch genauer Betrachtet werden, und wie man mit Bytestrings umgeht. Nimmt man an, dass die in einem Encoding vorliegen? Oder fällt man zurück auf ASCII. Und dann ist halt noch das von birkenfeld angesprochene UCS2/4 Problem.
TUFKAB – the user formerly known as blackbird
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Donnerstag 27. September 2007, 08:44

=Encodings
Hmm, I see. Die Sache mit den Encodings scheint dann wirklich ein Problem darzustellen. Das es so kompliziert ist hätte ich nicht gedacht; kenne mich aber mit den *internen* Umsetzung von Encodings auch nicht aus.

Mein Vorstellung war dahingehend, das ich über Python Bordmittel schauen wollte welches Encoding vorliegt, und dann an `onig_new` das entsprechende `OnigEncoding` übergebe. Das ist aber insofern scheiße, da encoding guess total ineffizient ist (Zumindest auf Python Seite nicht schnell genug(?). Müsste man auf C verlegen, oder? Wie macht das SRE(?)).

Ich muss sagen das Thema Encoding und dessen interne Realisierung übersteigt mein Wissen! Bei dem Punkt bin ich raus.

=UCS2/UCS4
Das hängt doch aber auch vom build ab oder? So weit ich das hier verstehe ist `Py_UNICODE` von type `wchar_t` und je nach build `unsigned short` oder `unsigned long`.

Onigurumas `OnigUChar` ist ein typedef auf `unsigned char`. In `onig_search` wird er für den zu durchsuchenden string genutzt (WTF?!). `unsigned char` ist doch ein byte und ein cast von `unsigned short` auf `unsigned char` ist nicht möglich, weil der Wertbereich zu gering ist. So langsam aber sicher bezweifel ich ob sich Oniguruma überhaupt ohne unverhältnismäßigen Aufwand vollständig wrappen lässt.

Irgendwelche Vorschläge?

=Oniguruma struct`s über ctypes
@blackbird: Es geht, ich habe fast alle struct`s in ctypes definieren können und scheinen auch zu Funktionieren (Hoffentlich). Das wirklich schwierigste war `OnigEncodingType`, da ich erstmal raus finden musste wie man Sachen der Form

Code: Alles auswählen

int (*is_mbc_newline)(const OnigUChar *p, const OnigUChar *end);
umsetzt. Auch

Code: Alles auswählen

int (*apply_all_case_fold)(OnigCaseFoldType flag, OnigApplyAllCaseFoldFunc f, void* arg);`
war nicht einfach, da `OnigApplyAllCaseFoldFunc ` ein callback der form

Code: Alles auswählen

typedef int (*OnigApplyAllCaseFoldFunc)(OnigCodePoint from,
                                        OnigCodePoint* to, int to_len, void* arg);
ist. Hat ein wenig gedauert bis ich die struct mit solchen Membern in ctypes hinbekommen habe.


[1] Um sicherzustellen das die unter ctypes nachgebaute `OnigEncodingType` Funktioniert, habe ich mir `OnigEncodingType` in stark minimierter Form in eine C Datei mit dazugehörigen Testcode gepackt. Das ganze dan mit ctypes eingebunden und getestet. Schien zu laufen. Aber ob`s 100%ig Funktioniert, wird sich erst zeigen.


=Python C API
Müsste ich mich erst einarbeiten; und das ist nicht von Heute auf Morgen geschehen.

mfg
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Donnerstag 27. September 2007, 15:49

Also mein oniguruma wrapper (aka ponyguruma) sieht momentan so aus: http://dev.pocoo.org/hg/sandbox/file/tip/ponyguruma/

Und er matcht noch nicht, und ehrlichgesagt hab ich auch gerade die Lust verloren den Bug zu suchen ^^
TUFKAB – the user formerly known as blackbird
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Donnerstag 27. September 2007, 16:11

Hi, kurz überfolgen. Werde mir den Code gleich näher anschauen.
Wann genau hast du damit angefangen den zu schreiben, wenn man mal fragen darf?

EDIT: Hehe, wie ich sehe hast das gleiche Prob mit ``ONIG_ENCODING_KOI8``. :D

EDIT2:
Wow! Schaut sehr gut aus! :)

Also so castest du den pystring nach unsigned char?

Code: Alles auswählen

state->string = (UChar*)((PyStringObject*)string)->ob_sval;
BTW: Ich arbeite heut Abend an das ctypes ding weiter. Dann könnte man das als fallback für die windows user nutzen ;)
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Donnerstag 27. September 2007, 21:12

poker hat geschrieben:Also so castest du den pystring nach unsigned char?

Code: Alles auswählen

state->string = (UChar*)((PyStringObject*)string)->ob_sval;
Weil oniguruma uchars mag das für den Moment die einfachste Lösung zum Testen ist. Die Unicode Probleme mach ich später eh noch weg. Hauptsache es tut was, dass ich testen kann :-)
BTW: Ich arbeite heut Abend an das ctypes ding weiter. Dann könnte man das als fallback für die windows user nutzen ;)
Da bau ich lieber einen Windows Build oder lass mir einen Bauen ^^

So. Hab den Bug mal rausgemacht, jetzt kann man ein paar Dinge damit tun (wenn es auch noch nicht schneidet):

Code: Alles auswählen

>>> from ponyguruma import Regexp
>>> r = Regexp("(?<foo>.)")
>>> m = r.search("blub")
>>> dir(m)
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__len__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'begin', 'end', 'names_to_index', 'span', 'spans', 'state']
>>> m.state
<ponyguruma._lowlevel.MatchState object at 0x50e128>
>>> dir(m.state)
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__']
>>> m.begin()
0
>>> m.end()
1
>>> m.names_to_index
{'foo': 1}
>>> m.begin("foo")
0
TUFKAB – the user formerly known as blackbird
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Freitag 28. September 2007, 06:03

Jetzt mal ernsthaft. Wann hast du genau angefangen das ding zu schreiben?
blackbird hat geschrieben: Da bau ich lieber einen Windows Build oder lass mir einen Bauen ^^
Kein Problem. Na, dann viel Spaß bei deinem neuen Projekt :) Ich such mir dann mal in der Zwischenzeit was anderes...
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Freitag 28. September 2007, 10:07

poker hat geschrieben:Jetzt mal ernsthaft. Wann hast du genau angefangen das ding zu schreiben?
Vor zwei Tagen.

Nutzt leider noch immer UTF-8 intern, aber es matcht jetzt:

Code: Alles auswählen

>>> from ponyguruma import *
>>> Regexp("<([a-z]+)>").search("haha <foo> hehe")[1]
'foo'
TUFKAB – the user formerly known as blackbird
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Freitag 28. September 2007, 10:30

Ironie nicht erkannt im zweiten Absatz? Ein wenig frech ist es ja schon da du mein Projekt geklaut hast. Beschissener ist es aber das du anscheinend garnicht interessiert bist an einer zusammenarbeit. Sei es drum, kannst es gerne haben.

BTW: Mein "fallback" matcht nun auch :) Konnte zwar nicht alles mit ctypes machen und habe daher ein par Zeilen in C geschrieben, aber es läuft nun endlich.

Ich wrapp da mal in der zwischen zeit die PCRE Regexe Engine :D ... falls du mir nicht zuvorkommst.

BTW2:
blackbird hat geschrieben:

Code: Alles auswählen

>>> from ponyguruma import *
>>> Regexp("<([a-z]+)>").search("haha <foo> hehe")[1]
'foo'

Code: Alles auswählen

Regexp("<([a-z]+)>").search("blubb <isa> ;)")[1][::-1]
/off
Benutzeravatar
mq
User
Beiträge: 124
Registriert: Samstag 1. Januar 2005, 19:14

Freitag 28. September 2007, 11:38

poker hat geschrieben:Ironie nicht erkannt im zweiten Absatz? Ein wenig frech ist es ja schon da du mein Projekt geklaut hast.
Geklaut? Du hast eine Idee gepostet, und blackbird hat angefangen, sie umzusetzen (uebrigens voellig unabhaengig von deinem Code). Niemand hindert dich dran, das auch zu tun, Ideen sind (sofern man sie veroeffentlicht) an sich Allgemeingut (oder sollten es sein, gewisse Teile bestimmter Industriezweige sehen das leider anders). Wenn du nicht willst, das jemand anders deine Ideen verwendet, dann behalt sie fuer dich.
Beschissener ist es aber das du anscheinend garnicht interessiert bist an einer zusammenarbeit. Sei es drum, kannst es gerne haben.
Oeh, wo sagt er hier, dass er das alleine machen will? Im Gegensatz zu dir veroeffentlich er sogar seinen Code (und aktualisiert das Ganze sogar regelmaessig), waehrend du hier rumflamest. Irgendwie sieht das fuer mich so aus, als seist du da deutlich weniger kooperativ als er.
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Freitag 28. September 2007, 11:48

poker hat geschrieben:Ironie nicht erkannt im zweiten Absatz? Ein wenig frech ist es ja schon da du mein Projekt geklaut hast. Beschissener ist es aber das du anscheinend garnicht interessiert bist an einer zusammenarbeit. Sei es drum, kannst es gerne haben.
Mann nennt's auch Freiheit. Wenn du's so schlimm findest, solltest du Python nich benutzen, find ich oO' Ich fänds gut, wenn sich jemand an meinem geistigen Gut ergötzt... Auch wenn er genau dasselbe macht. Irgendwas is immer anders...

Immerhin gibts auch mehrere Implementationen von dieser .net Geschichte... IronPython und .netpy oder so oo' Und ironpython hat sich durchgesetzt. Oft basieren dann Projekte auf dem Code eines anderen oder auf der Idee und dadurch entsteht was grossartiges. Das find ich ja so schön an Open Source.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Freitag 28. September 2007, 23:05

Kleines Statusupdate: der Wrapper kann jetzt direkt mit Unicodestrings umgehen.

Außerdem ist quasi die gesamte Funktionalität von sre implementiert. Nächster Schritt: Tests und Doku schreiben... :cry:
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Samstag 29. September 2007, 01:23

birkenfeld hat geschrieben:Außerdem ist quasi die gesamte Funktionalität von sre implementiert. Nächster Schritt: Tests und Doku schreiben... :cry:
Und dann noch einen Benchmark, damit man weiß ob das ganze auch was gebracht hat. Die erweiterten Oniguruma Features alleine sind nicht gerade ein Totschlag Argument für eine weitere Library :-)

@poker: Ich geh auf die Anschuldigungen jetzt nicht weiter ein, niemand hindert dich daran sich dem Projekt anzuschließen. Da gibts genug zu tun.
TUFKAB – the user formerly known as blackbird
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Samstag 29. September 2007, 23:34

Benchmark gibts jetzt einen, aber der ist eher ein Argument für sre:
5.2 Sekunden versus 0.2 Sekunden fürs kompilieren von 10000 Regular Expressions, 5.8 fürs Matchen der selbigen versus 0.5. Die besseren Werte stehen auf der Seite von SRE. Möglicherweise ist der Benchmark auch einfach komplett falsch, wer Lust hat kann was besseres Beisteuern.

Ansonsten ist das Ding jetzt schon auf SRE Level, birkenfeld arbeitet noch an Python-Escapes (Oniguruma hat da andere) und dann müsste man noch ein paar der Funktionen vom Python Layer nach C umlegen (zum Beispiel die sub() Funktion), aber so wie es scheint ist das Performance Problem in Oniguruma selber.

Die History Groups sind auch noch nicht verfügbar, da stellt sich aber die Frage wie die in Python dargestellt werden sollen. Übergibt man da start()/end()/span()/group() dann mehrere Argumente? Oder ein Tuple? Wie sieht der Rückgabewert aus. etc.
TUFKAB – the user formerly known as blackbird
Antworten