[QUIZ#1] OnlyFoo (Python)


OnlyFoo

Erfahrenes Mitglied
#1
Das eigentliche Matchen läuft in zwei Zeilen, der Rest ist nur, damit das Programm hübsch verwendet werden kann :)

Code:
# -*- encoding: utf-8 -*-
import re

"""
    Quiz #1
    
    Der Fuzzy Matcher erledigt die geforderte Aufgabe eigentlich in einem
    Zwei-Zeiler.
    
    regex = re.compile( "(.*)%s(.*)" % \
            "(.*?)".join( "%s" % re.escape(x) for x in query if x.strip() ), \
            re.IGNORECASE )
    query_matches = regex.match( word ) != None )
    
    Am Beispiel JFK:
    Der Suchbegriff wird in einen regulären Ausdruck umgewandelt,
    indem zwischen alle Buchstaben beliebige Zeichen gematched werden können.
    (greedy für die Übersicht beim Highlight, Whitespaces weggelassen)
    
    JFK wird also zu: (.*?)J(.*?)F(.*?)K(.*)
    Dieser Ausdruck wird nun auf das zu prüfende Wort angewand, und, wenn er
    matched, dann haben wir was gefunden! =)
    
"""
class FuzzyMatcher( object ):
    """
        Initialisiert einen FuzzyMatcher mit einem gegebenen Suchbegriff.
    """
    def __init__( self, query, case_sensitive = False ):
        self._query = query
        self._regex = re.compile( "(.*?)%s(.*)" % \
            "(.*?)".join( "%s" % re.escape(x) for x in query if x.strip() ), \
            0 if case_sensitive else re.IGNORECASE )
    
    """
        Prüft ob 'word' auf den Suchbegriff passt und gibt je nach Ergebnis
        True oder False zurück
    """
    def match( self, word ):
        return self._regex.match( word ) != None
    
    """ Wenn 'word' als ein Suchergebnis identifiziert wurde,
        wo werden alle Vorkommen des Suchbegriffes markiert..
        Falls nicht, wird ein ValueError geworfen
    """
    def highlight( self, word ):
        match = self._regex.match( word )
        if not match:
            raise ValueError( "word does not match the query" )
        
        query = self._query
        result = []
        is_open = False
        groups = match.groups()
        for index in range( len( groups ) ):
            this = groups[index]
            next = groups[index+1] if index < len( groups ) - 1 else None
            
            # Wir befinden uns nicht zwischen zwei
            # aufeinander folgenden, gefundenen Buchstaben
            if this:
                # die Markierung ist noch offen. Wir schließen sie
                if is_open:
                    result.append( ">" )
                    is_open = False
                
                # Wir kopieren ein Stück Text, was zwichen > und < vorkommt
                # in unser Ergebnis
                result.append( this )
                
                # Wir sind nicht am Ende, also Markierung öffnen
                if next != None:
                    result.append( "<" )
                    is_open = True
                    # Und einen Buchstaben aus unserer Suchanfrage anhängen
                    result.append( query[:1] )
                    query = query[1:]
            
            # Wir befinden uns direkt zwischen zwei gefundenen Buchstaben
            else:
                # Die Markierung ist noch nicht offen,
                # wir befinden uns also direkt am Anfang der Zeile
                # Wir öffnen sie
                if not is_open:
                    result.append( "<" )
                    is_open = True
                
                # Wir kopieren einen Buchstaben unserer Suchanfrage...
                result.append( query[:1] )
                query = query[1:]
                
                # Wir befinden uns am Ende der Zeile, wir müssen
                # noch die Markierung schließen
                if next == None:
                    result.append( ">" )
                    is_open = False
                
        # Ergebnis zusammentun und zurück geben
        return "".join( result )


import getopt, sys

def usage():
    print "%s  [-e] [-s] [-i input-file] query" % sys.argv[0]
    
def __main__():
    # Argumente parsen
    try:
        opts, args = getopt.getopt( sys.argv[1:], "sei:" )
    except getopt.GetoptError, err:
        print str( err )
        usage()
        sys.exit(1)
    
    # Argumente auswerten und zuweisen
    case_sensitive = False
    extended = False
    input_file = "presidents.txt"
    for option, value in opts:
        if option == '-i':
            input_file = value
        
        elif option == "-e":
            extended = True
        
        elif option == "-s":
            case_sensitive = True
    
    # Gucken ob wir einen Suchbegriff haben
    if len( args ) != 1:
        usage()
        sys.exit(2)
    
    # den Matcher erstellen
    matcher = FuzzyMatcher( args[0], case_sensitive ) 
    
    # Zeile für Zeile durch die Datei gehen
    fp = open( input_file, "r" )
    for line in fp:
        line = line.strip()
        # und gefundene Begriffe ausgeben
        if matcher.match( line ):
            print matcher.highlight( line ) if extended else line

    # Ordnung muss ein
    fp.close()

if __name__ == "__main__":
    __main__()
 

Neue Beiträge