Seite 1 von 1

Regex-Frage

Verfasst: Freitag 19. März 2004, 18:20
von mawe
Hi!

Ich bin die Regex-Syntax von Perl gewohnt und stehe bei folgendem Code etwas auf der Leitung:

Code: Alles auswählen

from re import *
antwort={"x":"gut","y":"schlecht"}
s="Python ist x"
a=sub("(x)",antwort[r'\1'],s)
print a
Das x soll also durch den entsprechenden Wert aus dem Dictionary ersetzen.
Funktioniert so aber nicht wirklich :-(

Bitte helft mir!

Verfasst: Freitag 19. März 2004, 18:47
von Milan
Hi. Für sowas verbrät man in Python aber keine kostbare Laufzeit mit teuren RE's. Da kannst du Strings ganz anders formatieren:

Code: Alles auswählen

a="Python ist %(x)s" % {"x":"gut","y":"schlecht"}
Zum Stringformatieren mittels einfügen von Werten gibts noch einiges mehr an Funktionalität... :wink:

Ansonsten werden RE's anders benutzt:

Code: Alles auswählen

a=sub("x",antwort["x"],s)
hth, Milan

Verfasst: Freitag 19. März 2004, 19:01
von mawe
Hi Milan!

Erstmal danke für die schnelle Antwort.

Mein Beispielcode war etwas (naja, sehr) schlecht gewählt :-)
Was ich eigentlich will ist folgendes:
Ich habe z.B. die Formel H2O und möchte nun das H und das O durch die entsprechenden Molmassen, die in einem Dictionary stehen ersetzen.

Mit den beiden Möglichkeiten die Du mir angeboten hast geht das nicht wirklich (so weit ich das verstehe).

Ich dachte das wäre eine tolle Aufgabe für eine Regex. Oder doch nicht?

Verfasst: Freitag 19. März 2004, 19:59
von Milan
Hi. Hmm, so ganz einleuten tuts mir noch nicht. Wenngleich es mich interessiert (hab Chemie LK), versteh ich noch nicht ganz, was rauskommen soll. So wie ich dich verstanden habe, willst du also aus einem "H2O" ein z.B. "(1g/mol)2(16g/mol)" machen, oder ? :wink: Bei solchen Sachen muss ich mir auch immer erst was bildlich vorstellen können, bevor ich dann was progge. Kannst du mir also bitte noch ein kleines Beispiel geben?

Milan

Verfasst: Freitag 19. März 2004, 20:14
von mawe
Hi!

Ja, meine Erklärungen sind nicht gerade die besten ;-)

Also, folgendes soll das Script können:
Ich gebe eine Formel ein, z.B. H2O, rauskommen soll die Molmasse, in diesem Fall ca. 18.

Nun habe ich mir gedacht, ich wandle die Formel mal in etwas um, das ich dann mit eval auswerten kann, hier also 1.0079*2+15.999.

Den Teil mit *2+ hab ich schon erledigt, nun fehlen noch das H und O. Die Molmassen der einzelnen Elemente stehen wie schon gesagt in einem Dictionary.

Ich bin mir nicht sicher ob das ein sinnvoller Weg ist. Bin für andere Vorschläge offen!

Verfasst: Freitag 19. März 2004, 21:04
von Milan
Hi. Tja, für relativ einfache Formeln mag das ja gehen, aber was wenn dann schwierigere kommen? Bsp: Kaliumhexacyanoferrat(III) == K3[Fe(CN-)6]

Da ist ja auch ein "-" mit drin, ich weiß nicht wie das dein Programm umsetzen würde, aber da könnte es zu Problemen kommen (eventuell durch eine leere Zeichenfolge ersetzen lassen).

Ich würde an deiner Stelle rekursiv vorgehen: mittels RE's immer wieder Gruppen der Form "\[.+?\]\d*", "\(.+?\)\d*" und "[A-Z][a-z]?\d*" abspalten (in der Reihenfolge) und die dann analysieren. Das \d stellt dar, wieviel mal du den Ausdruck nehmen muss. Irgendwann ist dein Programm dann rekursiv soweit angelangt, dass nur noch Gruppen der letzen Art betrachtet werden, die de facto ein Atom darstellen (z.B. "H2"). Dann dürftest du das haben, was du wolltest.

hth, Milan.

ps: kann leider aus Zeitmangel nicht mit Quelltexten helfen, da ich über das WE viel zu tun hab. Ich hoff mal du / jemand anderes hier kann das nach dem Kozept fertig machen.

Verfasst: Freitag 19. März 2004, 21:46
von Dookie
Hi mawe,

hier ist mal ein Beispielcode für einen Parser, allerdings ohne re

Code: Alles auswählen

elemente = {"H" : "1.0079", "O" : "15.999"}

class parser(object):
    def __init__(self, s):
        self.i = 0
        self.s = s
        
    def get_elem(self):
        """ lese Element-ID aus self.s """
        e = ""
        try:
            while not self.s[self.i].isupper():
                self.i += 1
            e += self.s[self.i]
            self.i += 1
            while self.s[self.i].islower():
                e += self.s[self.i]
                self.i += 1
        except IndexError:
            pass
        return e
        
    def get_int(self):
        """ lese Integer aus self.s """
        e = ""
        try:
            while not self.s[self.i].isdigit():
                self.i += 1
            while self.s[self.i].isdigit():
                e += self.s[self.i]
                self.i +=1
        except IndexError:
            pass
        return e
    
    def parse(self):
        self.i = 0
        result = ""
        while True:
            try:
                if self.s[self.i].isupper(): # Zeichen ist Grossbuchstabe
                    result += "+"+elemente[self.get_elem()]
                elif self.s[self.i].isdigit(): # Zeichen ist Nummer
                    result += "*"+self.get_int()
                else: # unbekanntes Zeichen überlesen
                    self.i += 1
            except IndexError:
                break
        return result

eingabe = raw_input("Formel eingeben: ")
print parser(eingabe).parse()

Gruß

Dookie

Verfasst: Freitag 19. März 2004, 22:24
von Milan
Hi. Nicht schlecht, aber buggy :wink: K3[Fe(CN-)6] bringt bei mir "+39*3+56+12+14*6", richtig wäre aber "+39*3+56+12*6+14*6".

So. Hab mir jetzt doch die Zeit genommen:

Code: Alles auswählen

import re

elemente={"H" : 1, "O" : 16,'Fe':56,'K':39,'C':12,'N':14}
eckig=re.compile("\[(.+?)\](\d*)")
rund=re.compile("\((.+?)\)(\d*)")
normal=re.compile("([A-Z][a-z]?)(\d*)")


def M(s):
    if s=="":
        return 0
    mi=eckig.match(s)
    if not mi:
        mi=rund.match(s)
    if not mi:
        mi=normal.match(s)
        atom,n=mi.groups()
        if n:
            n=int(n)
        else:
            n=1
        return elemente[atom]*n+M(s[mi.end():])
    subgroup,n=mi.groups()
    if n:
        n=int(n)
    else:
        n=1
    return M(subgroup)*n+M(s[mi.end():])
"+" und "-" müssen vorher durch "" ersetzt werden, geht durch ein einfaches replace.

Milan

Verfasst: Samstag 20. März 2004, 18:53
von Gast
Hi!


Tut mir leid, daß ich mich erst so spät wieder melde.

Ihr zwei (Milan,Dookie) seid genial!
Muß mir eure Beiträge jetzt mal genauer anschaun, um sie zu verdauen ;-)

Vielen Dank!!!

Verfasst: Samstag 20. März 2004, 18:56
von mawe
Naja, vielleicht sollte ich einloggen, bevor ich was schreibe. Nochmals danke :-)