Zur Navigation

Sprachweiche [5]

mit weiteren seltsamen RegEx-Problemen

41 Ranma (Gast)

Ich versuche zur Zeit die als heruntergeladenen Dateien vorhandenen Wörterlisten in Datenbanktabellen zu überführen. Die Wörterlisten sind leider nicht einheitlich. So muß ich das Skript an jede neu anpassen. Schon mit der ersten Wörterliste (Niederländisch) habe ich MySQL an seine Grenzen getrieben. Das schließe ich daraus, daß phpMyAdmin immer wieder eine andere Anzahl an Einträgen in die Tabelle anzeigt. Man braucht lediglich die Seite neu zu laden und ohne etwas verändert zu haben steht dann wieder eine andere Zahl da. Die Zahlen liegen zwischen 150 000 und 240 000 Einträgen. Wieviele Einträge kann eine Tabelle haben, bevor MySQL ins Schwimmen kommt?

Es ist völlig klar, daß eine einfache Wörterliste, die nichtmal Anspruch auf Vollständigkeit erhebt, nicht zu so vielen Einträgen führen sollte. Üblicherweise kennt ein gebildeter Mensch ungefähr fünftausend Wörter seiner Muttersprache. Fremdsprachler und weniger gebildete Menschen sollten zwischen zweitausend und dreitausend Wörter beherrschen. Darum würde ich davon ausgehen, daß die Datenbank eines schon länger etablierten Wörterbuches eher um die fünftausend Wortpaare enthält. Die Nichteindeutigkeit von Rückübersetzungen berücksichtigend, könnten es auch zwanzigtausend bis vierzigtausend sein. Aber kaum über fünfzigtausend. Eine Datenbank mit mehr als zwanzigtausend solcher Einträge ließe sich wahrscheinlich schon noch besser organisieren, so daß es weniger Einträge würden.

Tatsächlich kommen in den Wörterlisten häufig Wiederholungen vor. Es wäre natürlich sinnvoll, die nur einmal einzutragen. Es gibt zwar viele Tutorials, die erklären, wie man eine doppelte Eintragung aus einem Formular verhindert, aber es ist etwas ganz anderes, wenn man eine Quelle vorliegen hat, die viele einfache Einträge enthält, aber darunter dann doch doppelte und mehrfache. Das einfache Eintragen dauerte schon Stunden. Aber wegen einiger (mit Regulären Ausdrücken verursachten) Fehler muß ich das wohl nochmal machen. Dabei sollte ich die Wiederholungen vermeiden. Muß ich vor jedem Eintrag die ganze Tabelle auf Duplikate untersuchen? Ich befürchte nämlich, daß die benötigte Zeit dann gegen unendlich gehen dürfte. Oder es zumindest Tage dauert, um das Skript einmal laufen zu lassen. Dabei wüßte ich nichtmal ob es funktioniert oder ob ich das Skript nicht besser abbrechen sollte.

Wahrscheinlich wird PHP auch nicht mitmachen, wenn ich vorher versuche, erstmal alles in einem Array mit ungefähr zweihundert Elementen zwischenzulagern, nur um darin die gleichen Elemente löschen zu können.

In MySQL gibt es DISTINCT für SELECT und man kann Tabellenspalten auf UNIQUE setzen. Aber ich brauche so etwas für die Kombination zweier Spalten beim INSERT. Was kann ich da tun? Oder kann ich zumindest hinterher gleiche Einträge wieder loswerden? Jeder Eintrag hat eine fortlaufende Indexnummer, weil MySQL einen Key verlangt und es jedes Tutorial so macht und ich es dann so nachmache. Der gesamte Eintrag ist dadurch nicht gleich, aber die Kombination der nächsten beiden Spalten kann gleich sein und das sollte nicht sein.
Ranma

15.10.2015 13:41

42 Ranma (Gast)

Ich habe IF(EXISTS(SELECT...),,INSERT...) versucht, zur Vermeidung doppelter Einträge. Möglicherweise kann man aber IF nur hinter einer anderen Anweisung verwenden?

Jedenfalls beschwerte sich MySQL wieder darüber, daß mein Statement kein Statement, sondern ein Boolean sei. Darüber beschwert sich MySQL auffallend oft. Praktisch immer, wenn ich in eine Query ein AND oder ein OR einbaue. Der Versuch der Query mit IF enthält auch ein AND, um zwei Datenbankspalten zu kombinieren, weil erst die Kombination einmalig sein muß. Kann es sein, daß sich AND und OR nicht mit der Verwendung von Prepared Statements vertragen?
Ranma

16.10.2015 01:36

43 Ranma (Gast)

TRUNCATE TABLE funktionierte sehr schnell.

Das Problem mit dem Boolean scheint nicht selten zu sein, wird aber meistens durch offensichtliche Fehler wie fehlende Spaltennamen in der Query verursacht.

Mein Versuch einer Query ist wohl übertrieben. Wahrscheinlich brauche ich lediglich PRIMARY KEY (Deutsch, Fremdsprache) als eine SQL-Anweisung für jede meiner Wörterbuch-Tabellen. Ich habe nur nicht herausgefunden wie sich diese Kombination mit phpMyAdmin einstellen läßt. Aber es sollte genügen, diese Anweisung einfach einmal an die Datenbank zu senden.
Ranma

16.10.2015 02:35

44 Jörg Kruse

Das schließe ich daraus, daß phpMyAdmin immer wieder eine andere Anzahl an Einträgen in die Tabelle anzeigt. Man braucht lediglich die Seite neu zu laden und ohne etwas verändert zu haben steht dann wieder eine andere Zahl da. Die Zahlen liegen zwischen 150 000 und 240 000 Einträgen. Wieviele Einträge kann eine Tabelle haben, bevor MySQL ins Schwimmen kommt?

Du meinst auf der Übersichtseite von phpMyAdmin? da werden bei größeren Tabellen nur Näherungswerte angezeigt - vermutlich damit die Seite bei einer großen Anzahl von Tabellen nicht so lange zum Laden braucht. Einen genauen Wert zu einer einzelnen Tabelle erhältst du durch eine COUNT(*)-Abfrage.

In MySQL gibt es DISTINCT für SELECT und man kann Tabellenspalten auf UNIQUE setzen. Aber ich brauche so etwas für die Kombination zweier Spalten beim INSERT. Was kann ich da tun?

Ein Index kann auch mehrere Spalten enthalten - einen solche mehrspaltigen Index kannst du dann auch als UNIQUE definieren.

16.10.2015 11:14 | geändert: 16.10.2015 11:15

45 Ranma (Gast)

Ja, die Übersichtsseite habe ich gemeint. Die haut tatsächlich auch bei wenigen Einträgen einfach irgendeine Zahl raus. Der Link zum Anzeigen der Datensätze, das habe ich inzwischen festgestellt, führt zu einer konsistenten Zahl. War also falscher Alarm.

Beim PRIMARY KEY mußte ich etwas herumprobieren. Eine Kombination aus Datenbankspalten läßt sich nicht einfach als Eigenschaft einstellen, sondern erfordert eine Query. Wird aber kein PRIMARY KEY definiert, dann ernennt MySQL eigenmächtig eine geeignete Tabellenspalte dazu. Die muß man dann erst löschen, bevor man einen PRIMARY KEY aus einer Kombination erstellen kann. Außerdem muß man Schlüssellängen angeben (die mir nach wie vor garnichts sagen) und das in der Query, aber nicht als Spalteneigenschaft, wo die Angabe einer Länge in dem Fall garnichts bringt. Das war etwas verwirrend. Aber jetzt habe ich es hinbekommen.

Ich habe schon ein paar Tabellen befüllt. Sogar schon ein paar Fehler ausgebügelt. Die Wörterlisten, die mir als Dateien vorliegen, wurden ziemlich disziplinlos erstellt. Die enthaltenen Fehler werde ich nicht so schnell los, die ausgebügelten habe ich selbst gemacht. Jetzt versuche ich, MySQL irgendwie dazu zu bringen festzustellen, ob ein Wort mit einem Großbuchstaben beginnt. Aber es weigert sich.

Mit PHP bekomme ich das inzwischen hin. Ergebnisse kann ich von da aus an MySQL schicken. Aber angeblich soll man Statements nicht in Schleifen auf eine Datenbank abfeuern. Gäbe es nicht viele Ergebnisse, dann bräuchte ich keine Datenbank. Die Schleife brauche ich wiederum, um viele Ergebnisse zu erhalten. Wie sollen die Ergebnisse sonst in die Datenbank kommen, wenn nicht aus der Schleife?

Beim Problem des Boolean, wo ein Statement sein sollte, war ich zu hochnäsig. Ich hatte eine Tabellenspalte umbenannt und das meinem Prepared Statement nicht mitgeteilt. Also hatte ich doch das selbe Problem, das ich bei den Beispielen anderer offensichtlich fand. Wenn sich MySQL zukünftig über Booleans beklagt, dann weiß ich, daß ich als allererstes nach den Tabellennamen und Spaltennamen schauen muß.
Ranma

17.10.2015 01:12

46 Jörg Kruse

Jetzt versuche ich, MySQL irgendwie dazu zu bringen festzustellen, ob ein Wort mit einem Großbuchstaben beginnt. Aber es weigert sich.

Das kann auch am Encoding der Tabelle liegen. Ein _ci am Ende wie z.B. im Standardzeichensatz latin1_swedish_ci bedeutet "case insensitive", so dass MySQL dann bei der Suche Groß- und Kleinschreibung nicht berücksichtigt

Die Schleife brauche ich wiederum, um viele Ergebnisse zu erhalten. Wie sollen die Ergebnisse sonst in die Datenbank kommen, wenn nicht aus der Schleife?

Du kannst mit einer INSERT-Abfrage mehrere Datensätze einfügen, Beispiel aus dem Manual:

INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

Das VALUES Statement kann man auch in einer PHP-Schleife erstellen

17.10.2015 17:05 | geändert: 17.10.2015 17:06

47 Ranma (Gast)

Ach dafür steht ci. Ich habe es zwar endlich geschafft, daß MySQL utf-8 als Voreinstellung akzeptiert, aber ci hängt so ziemlich überall dran. Also meine Funktionen zur Feststellung der Großschreibung haben eigentlich gleich funktioniert, nur war das dem Vergleich dann egal. Da muß man erst draufkommen und dann noch einen Weg suchen, um das zu umgehen. So einen Vergleich verwendet man natürlich im WHERE-Teil. Der Vergleich funktioniert, wenn man nach WHERE die Option BINARY einfügt.

Um das Verhindern doppelter Einträge nachzumachen, muß man auch da noch eine Option kennen. Zwischen INSERT und INTO muß da noch ein IGNORE. Erst dann werden gleiche Einträge verworfen statt Fehlermeldungen zu produzieren.

Alle Values auf einmal in einer Query unterzubringen, das mag für drei bis vier Einträge funktioneren. Um eine Liste aus tausenden Einträgen in eine Datenbanktabelle zu überführen ist das wohl doch unpraktikabel. Ich wüßte auch garnicht, was gegen das Ausführen einer Query innerhalb einer Schleife sprechen soll.

Es gibt sogar eine SQL-Funktion, um eine Datei zeilenweise in eine Tabelle einzulesen. Ich muß nur PHP verwenden, weil die Listen uneinheitlich und undiszipliniert aufgebaut sind. Zum Beispiel befindet sich manchmal die Aussprache angegeben, meistens zwischen eckigen Klammern, manchmal zwischen Backslashes, aber manchmal befinden sich grammatische Angaben zwischen Backslashes oder die eckigen Klammern werden verwendet für Angaben wie [math.] und das in der gleichen Zeile wie [], also leere eckige Klammern, wo in anderen Zeilen der gleichen Liste die Aussprache angegeben ist. Wegen solcher Sachen muß ich mein einlesendes Skript für jede Liste modifizieren. Natürlich baue ich jedesmal mindestens einen Fehler ein, so daß ich den stundenlang suchen muß. Ich habe fast einen ganzen Tag gebraucht, um herauszufinden, daß eine ) zwei Stellen zu weit rechts war. Das hatte zu keiner Fehlermeldung geführt, sondern war nur an fehlenden Einträgen in die Datenbanktabelle zu erkennen.

Ein paar Listen habe ich also immernoch einzulesen. Leider ist das frei lizenzierte Chinesisch-Wörterbuch Handedict seit einigen Wochen verschwunden, ausgerechnet jetzt, wo ich ein Wörterbuch baue. Die Datenbank hätte ich wirklich gerne in meine aufgenommen.
Ranma

18.10.2015 02:15

48 Ranma (Gast)

Hier sind mal zwei Beispiele für undisziplinierte Wörterlisteneinträge:

binden [bindən]
     bound}, link, spellbound}, to bind {bound, to ligate, to
     link, to spellbind {spellbound, to tie

funktionieren [fuŋktsiːoːniːrən]
     function, gone}, to act, to go {went, to perform, to work,
     to work {worked, worked, wrought, wrought}

Außer daß eine geschweifte Klammer irgendwo öffnet und irgendwo schließt, kommt auch vor, daß eine geschweifte Klammer öffnet und dann eine eckige Klammer schließt oder einfach keine schließende Klammer existiert.

Man sieht hier auch, daß ein Eintrag immer mit einer nichteingerückten Zeile beginnt und dann von eingerückten Zeilen gefolgt wird. Das nutze ich, um beide Sprachen voneinander zu unterscheiden. Leider gibt es auch Listen bei denen das nicht funktioniert. Es gibt zum Beispiel welche mit zusätzlichen Zeilen, in denen eine Anmerkung in runden Klammern steht. Die Aussprache, die in den Beispielen direkt auf das Wort in eckigen Klammern folgt, kann auch in einer extra Zeile stehen. In solchen Fällen trägt mein Skript ein ziemliches Durcheinander in die Datenbanktabelle ein.

In den gezeigten Beispielen werden die Übersetzungsvarianten, die jeweils ein Paar mit dem zu übersetzendem Wort bilden sollen, über einen Zeilenumbruch hinweg fortgeführt. Das heißt im Array, in das ich die Datei über file() einlese, steht in einem Element 'to' und im nächsten 'link', wo es eine Übersetzung 'to link' geben sollte. Dazu noch das Durcheinander mit den geschweiften Klammern, das ebenfalls zeilenübergreifend auftritt. Das zweite Beispiel soll außerdem zeigen, daß ich die zusammengehörenden Verbformen nichtmal durch die Anfangsbuchstaben zuordnen könnte. Das erste Beispiel zeigt das größere Durcheinander, weil da nicht nur jeweils die schließende vor der öffnenden Klammer steht, sondern die beiden sich auch noch irgendwie überkreuzen und dazu noch mit weiteren Wörtern.

Hat irgendjemand hier eine Idee, wie ein Skript da Ordnung hineinbringen könnte?
(Mal abgesehen davon, daß 'to' vor jedem Verb für solche Listen unüblich ist.)
Ranma

19.10.2015 03:33

49 Jörg Kruse

Hat irgendjemand hier eine Idee, wie ein Skript da Ordnung hineinbringen könnte?

Vielleicht erstmal ein Script drüber laufen lassen, welches kaputte Einträge, z.B. solche mit falsch positionierten geschweiften Klammern, identifiziert, und diese für eine Korrektur aussortiert.

19.10.2015 17:06

50 Ranma (Gast)

Ja, natürlich muß ich die kaputten Einträge identifizieren lassen. Aber woran würde das Skript einen kaputten Eintrag erkennen? Sie stehen scheinbar wild durcheinander. Aber solche kommen hunderte Male vor. Darum habe ich den Verdacht, daß das Durcheinander irgendwie automatisiert zustande gekommen ist. Die Liste war so auf Sourceforge.net zum herunterladen zu finden und ich übertrage sie nur in meine Datenbank. Darum kenne ich das Skript nicht, das die Liste erstellt hat. Ich weiß auch nicht sicher, ob sie wirklich mit einem Skript erstellt wurde. Aber hunderte Einträge, bei denen nicht einfach eine Klammer vergessen (das hielte ich bei vielen tausend Einträgen per Hand sogar für wahrscheinlich) wurde, sondern erst ein Stück mit schließender Klammer, dann irgendetwas anderes und dann ein Stück mit öffnender Klammer folgt, das bekommt man nicht mit per Hand erzeugten Fehlern hin? Falls das ein Skript war, dann muß es etwas gemacht haben, das sich rückgängig machen läßt?
Ranma

20.10.2015 02:31