Kreuzworträtzelhilfe

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
Rainier
User
Beiträge: 16
Registriert: Mittwoch 22. August 2007, 10:03

Mittwoch 22. August 2007, 10:29

Hallo,

ich bin ziemlich neu in der Python-Welt und fühle mich dort wohl. Insbesondere weil ich mir viele Hilfen aus diesem fantastischem Forum holen kann. Nun habe ich gedacht, ich zeige einmal, was ich hier alles gelernt habe:

Ich habe ein Skript gefertigt, dass beim Lösen von Kreuzworträtseln helfen soll. Man gibt in der GUI, die bekannten Buchstaben ein und füllt alle unbekannten Zeichen mit einem Minuszeichen auf. Beispiel: bei -a-s zeigt das Skript u.a. haus und maus an.

Hier der Code:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: iso-8859-1 -*-

import wx
import os

def create(parent):
    return Frame1(parent)

[wxID_FRAME1, wxID_FRAME1BUTTON, wxID_FRAME1EINGABE, wxID_FRAME1PANEL1, 
 wxID_FRAME1STATICTEXT1, wxID_FRAME1AUSGABE, 
] = [wx.NewId() for _init_ctrls in range(6)]

class Frame1(wx.Frame):
    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt,
              pos=wx.Point(82, 329), size=wx.Size(400, 250),
              style=wx.DEFAULT_FRAME_STYLE, title=u'Rätselhilfe')
        self.SetClientSize(wx.Size(392, 223))

        self.panel1 = wx.Panel(id=wxID_FRAME1PANEL1, name='panel1', parent=self,
              pos=wx.Point(0, 0), size=wx.Size(392, 223),
              style=wx.TAB_TRAVERSAL)

        self.staticText1 = wx.StaticText(id=wxID_FRAME1STATICTEXT1,
              label='Bitte Wortmuster eingeben (Minuszeichen gleich Platzhalter)',
              name='staticText1', parent=self.panel1, pos=wx.Point(8, 8),
              size=wx.Size(287, 13), style=0)

        self.eingabe = wx.TextCtrl(id=wxID_FRAME1EINGABE, name='eingabe',
              parent=self.panel1, pos=wx.Point(8, 24), size=wx.Size(376, 21),
              style=0, value='')

        self.button = wx.Button(id=wxID_FRAME1BUTTON, label=u'Lösungshilfe',
              name='button', parent=self.panel1, pos=wx.Point(8, 48),
              size=wx.Size(376, 23), style=0)
        self.button.Bind(wx.EVT_BUTTON, self.loesen, id=wxID_FRAME1BUTTON)

        self.ausgabe = wx.TextCtrl(id=wxID_FRAME1AUSGABE, name='ausgabe',
              parent=self.panel1, pos=wx.Point(8, 80), size=wx.Size(376, 144),
              style=wx.TE_MULTILINE, value='')
        self.ausgabe.SetAutoLayout(False)

    def __init__(self, parent):
        self._init_ctrls(parent)

    def loesen(self, event):
        suchwort = self.eingabe.GetValue()
        self.ausgabe.SetValue("")
        suchwort_laenge = len(suchwort)
        ausgabe = file(os.path.join(os.getcwd(),"woerter.dic"),'r')
        test = False
        count = 0
        while test == False:
            wort = ausgabe.readline()
            if wort == "":
                test = True
            else:
                wort = wort[0:len(wort)-1]
                if len(wort) == suchwort_laenge:
                    testwort = True
                    for i in range(suchwort_laenge):
                        if suchwort[i] != "-":
                            if wort[i] != suchwort[i]:
                                testwort = False
                    if testwort == True:
                        count += 1
                        self.ausgabe.WriteText(wort+"\n")
        ausgabe.close()
        self.ausgabe.WriteText("\n" + str(count) +" Wörter gefunden.\n\nSuchvorgang abgeschlossen.")
        event.Skip()
        
app = wx.PySimpleApp(0)
frame = Frame1(None)
frame.Show()
app.MainLoop()
Als Wörterbuch habe ich mir die deutsche Rechtschreibhilfe aus OpenOffice entliehen, die unter folgender URL http://ftp.services.openoffice.org/pub/ ... /de_DE.zip runtergeladen werden kann. (Entpacken nicht vergessen)

Um dieses für das Skript anzupassen, habe ich folgendes Zusatzskript gefertigt:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: iso-8859-1 -*-

'''
Wandelt das Wörterbuch von OOO in ein lesbares Format für das Script Rätselhilfe um
'''

dateiname_OOO_Dic = "de_DE.dic"

def main():
    print u"Ich wandel jetzt das Woerterbuch um."
    print "Bitte warten\n"
    eingabe = file(dateiname_OOO_Dic)
    ausgabe = file("woerter.dic","w")
    test = "false"
    while test == "false":
        wort = eingabe.readline().decode("iso-8859-15")
        if wort == "":
            test = "true"
        else:
            slash = wort.find("/")
            if slash:
               wort = wort[0:slash]
            wort = wort.lower()   
            wort = wort.replace(u"ä","ae")
            wort = wort.replace(u"ö","oe")
            wort = wort.replace(u"ü","ue")
            wort = wort.replace(u"ß","ss")       
            wort = wort.lower()
            ausgabe.write(wort.encode("iso-8859-15")+"\n")
    eingabe.close()
    ausgabe.close()
    
    print "Fertig"
    
if __name__ == '__main__':
    main()
Ich hoffe es ist zu gebrauchen.
BlackJack

Mittwoch 22. August 2007, 13:02

Ich dachte bei aktuellen `wx`-Versionen braucht man diese furchtbaren IDs nicht mehr selber zu erzeugen, sondern kann fast überall eine -1 übergeben!?

Warum nennst Du das Wörterbuch das *eingelesen* wird `ausgabe`? Und das aktuelle Arbeitsverzeichnis vor einen Dateinamen vor dem öffnen zu hängen ist überflüssig. Dort wird bei einem relativen Pfad ja sowieso nach der Datei gesucht.

Die ``while``-Schleifen bei den Dateien sind überflüssig. Man kann direkt mit ``for`` über Zeilen in Dateien iterieren. Damit spart man sich `test` und eine ``if``/``else``-Abfrage.

Um das letzte Zeichen einer Zeichenkette zu entfernen ist ``s = s[:-1]`` kürzer als ``s = s[0:len(s) - 1]``. In diesem Fall würde ich aber ``s = s.strip()`` benutzen. Das macht deutlicher was man machen möchte und entfernt auch eventuelle führende und folgende Leerzeichen. Damit ist das Programm etwas robuster, falls jemand das Wörterbuch mal per Hand bearbeitet.

Das testen auf ein Wort würde ich in eine Funktion auslagern und eventuell böten sich hier reguläre Ausdrücke an. Das macht das ganze etwas übersichtlicher. Insgesamt könnte man diese Logik von der GUI trennen. Und vielleicht auch bei Programmstart das Wörterbuch in ein Dictionary einlesen, das Wortlängen auf Wortlisten abbildet. Das wäre ein prima Objekt.

Zum Unwandlungsskript. Hier gilt für die ``while``-Schleife über die Datei das gleiche. Das (de)kodieren beim lesen und schreiben kann man eleganter über das `codecs`-Modul lösen.

Das suchen nach dem `slash` würde ich für einen Programmierfehler halten. Das ``if`` wird nur in einem einzigen Fall *nicht* ausgeführt -- nämlich wenn der '/' an erster Stelle im `wort` steht. Dann bleibt das Wort unverändert. Ansonsten wird mindestens das letzte Zeichen entfernt.

Zeichen ersetzen kann man ganz gut mit der `unicode.translate()`-Methode.

Code: Alles auswählen

import codecs
from collections import defaultdict
from itertools import ifilter, imap


class RaetselWoerterbuch(object):
    def __init__(self, woerter=()):
        self.data = defaultdict(list)
        self.woerter_hinzufuegen(woerter)
    
    def woerter_hinzufuegen(self, woerter):
        for wort in woerter:
            wort = wort.strip()
            self.data[len(wort)].append(wort)
    
    def suchen(self, muster):
        def test(wort):
            return all(a in ('-', b) for a, b in izip(muster, wort))
        return ifilter(test, self.data[len(muster)])
    
    @classmethod
    def laden(cls, dateiname):
        woerter = open(dateiname, 'r')
        result = cls(woerter)
        woerter.close()
        return result


def convert_word(word):
    prefix, splitted, dummy = word.partition('/')
    if splitted:
        word = prefix + '\n'

    table = { ord(u'ä'): u'ae',
              ord(u'ö'): u'oe',
              ord(u'ü'): u'ue',
              ord(u'ß'): u'ss' }
    return word.lower().translate(table)
    

def convert():
    in_file = codecs.open('/usr/share/myspell/dicts/de_DE.dic', 'r', 'iso-8859-1')
    out_file = codecs.open('test.txt', 'w', 'iso-8859-1')
    
    out_file.writelines(imap(convert_word, in_file))
    
    in_file.close()
    out_file.close()
Rainier
User
Beiträge: 16
Registriert: Mittwoch 22. August 2007, 10:03

Mittwoch 22. August 2007, 15:30

Vielen Dank BlackJack für Deine konstruktive Kritik. :)

Ich habe wieder mal festgestellt, dass ich immer noch diesen verflixten Spagethicode aus den alten GW-Basic-Zeiten verfallen bin. :evil: Aber Dank deiner Hilfe, habe ich bemerkt, dass vieles wirklich einfacher und auch übersichtlicher in Python zu gestalten ist. Ich werde weiter lernen.

Diese furchtbaren IDs habe ich leider drin, da ich aus Faulheit einen GUI-Builder benutzt habe. Darauf werde ich künftig wohl verzichten, denn es ist einfach besser zum Lernen, wenn man selbst Hand anlegt. :)
Antworten