Regex-Frage

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.
Antworten
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

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!
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

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
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

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?
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

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
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

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!
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

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.
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

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
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

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
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!!!
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Naja, vielleicht sollte ich einloggen, bevor ich was schreibe. Nochmals danke :-)
Antworten