Molare Masse erechnen mit Python?
Ich muss ein Programm programmieren, dass die Molare Masse eines eingegebenen Moleküls berechnen kann. Dafür muss das Programm aber Das eingegeben Wort unterteilen können. Also zB dass bei H20 dass O nicht mehr zu den H2 gehört, und dass die 2 der Multiplikationsfaktor der Molaren Masse ist. Die Rechnung setzt sich ja dann zusammen aus (2*H) + O. Was ist der Ansatz bei dieser Aufgabe?
4 Antworten
String muss mit einem Großbuchstabe beginnen, sonst ungültige Eingabe. Länge des Eingabestrings sinnvoll begrenzen.
Von links nach rechts lesen, verarbeiten mit:
https://de.wikipedia.org/wiki/Endlicher_Automat
Zustände: Element lesen, Index lesen.
Großbuchstabe oder Ziffer oder Stringende beenden das angefangene Element oder den Index (Cave: der Index kann auch mehr als eine Ziffer haben!)
Ein Element mit drei Zeichen, oder ein Element, das nicht in der Tabelle steht -> Abbruch wegen ungültiger Eingabe.
Ich habe so etwas Ähnliches einmal in JavaScript sehr einfach dadurch gemacht, daß ich aus dem Input-String (z.B. "Na2SO4") per Textsubstitution eine auswertbare Formel gebaut habe (z.B. "+23*2+32+16*4") und dann einfach deren Wert berechnet habe — letzteres geht in JavaScript leicht (eval), ich weiß nicht, ob Du das in Python nachbauen kannst. Es gilt dabei nur zu beachten, daß man bei der Reihenfolge der Substitutionen aufpassen muss (die zweibuchstabigen Elemente kommen vor den einbuchstabigen dran, sonst wird aus dem N von Natrium ein Stickstoff.
Zuerst definiere ich eine Liste von knapp 100 regexp-Substitutionen, die das Atomsymbol durch die molare Masse (mit einem Plus davor) ersetzen:
var amass= [ [/Ac/g,"+227"], [/Ag/g,"+107.8682"], [/Al/g,"+26.9815"], [/Am/g,"+243"], [/Ar/g,"+39.948"], [/As/g,"+74.9216"], [/At/g,"+210"], [/Au/g,"+196.9665"], [/Ba/g,"+137.327"], [/Be/g,"+9.0122"], [/Bi/g,"+208.9804"], [/Bk/g,"+247"], [/Br/g,"+79.904"], [/Ca/g,"+40.078"], [/Cd/g,"+112.411"], [/Ce/g,"+140.116"], [/Cf/g,"+251"], [/Cl/g,"+35.453"], [/Cm/g,"+247"], [/Co/g,"+58.9332"], [/Cr/g,"+51.9961"], [/Cs/g,"+132.9055"], [/Cu/g,"+63.546"], [/Dy/g,"+162.5"], [/Er/g,"+167.259"], [/Es/g,"+252"], [/Eu/g,"+151.964"], [/Fe/g,"+55.845"], [/Fr/g,"+223"], [/Ga/g,"+69.723"], [/Gd/g,"+157.25"], [/Ge/g,"+72.64"], [/He/g,"+4.0026"], [/Hf/g,"+178.49"], [/Hg/g,"+200.59"], [/Ho/g,"+164.9303"], [/In/g,"+114.818"], [/Ir/g,"+192.217"], [/Kr/g,"+83.8"], [/La/g,"+138.9055"], [/Li/g,"+6.941"], [/Lu/g,"+174.967"], [/Mg/g,"+24.305"], [/Mn/g,"+54.938"], [/Mo/g,"+95.94"], [/Na/g,"+22.9897"], [/Nb/g,"+92.9064"], [/Nd/g,"+144.24"], [/Ne/g,"+20.1797"], [/Ni/g,"+58.6934"], [/Np/g,"+237"], [/Os/g,"+190.23"], [/Pa/g,"+231.0359"], [/Pb/g,"+207.2"], [/Pd/g,"+106.42"], [/Pm/g,"+145"], [/Po/g,"+209"], [/Pr/g,"+140.9077"], [/Pt/g,"+195.078"], [/Pu/g,"+244"], [/Ra/g,"+226"], [/Rb/g,"+85.4678"], [/Re/g,"+186.207"], [/Rh/g,"+102.9055"], [/Rn/g,"+222"], [/Ru/g,"+101.07"], [/Sb/g,"+121.76"], [/Sc/g,"+44.9559"], [/Se/g,"+78.96"], [/Si/g,"+28.0855"], [/Sm/g,"+150.36"], [/Sn/g,"+118.71"], [/Sr/g,"+87.62"], [/Ta/g,"+180.9479"], [/Tb/g,"+158.9253"], [/Tc/g,"+98"], [/Te/g,"+127.6"], [/Th/g,"+232.0381"], [/Ti/g,"+47.867"], [/Tl/g,"+204.3833"], [/Tm/g,"+168.9342"], [/Xe/g,"+131.293"], [/Yb/g,"+173.04"], [/Zn/g,"+65.39"], [/Zr/g,"+91.224"], [/B/g,"+10.811"], [/C/g,"+12.0107"], [/F/g,"+18.9984"], [/H/g,"+1.0079"], [/I/g,"+126.9045"], [/K/g,"+39.0983"], [/N/g,"+14.0067"], [/O/g,"+15.9994"], [/P/g,"+30.9738"], [/S/g,"+32.065"], [/U/g,"+238.0289"], [/V/g,"+50.9415"], [/W/g,"+183.84"], [/Y/g,"+88.9059"], [/D/g,"+2.0141"], [/T/g,"+3.016"] ]
Der Rest ist dann sehr einfach:
function mmass(str)
{
var i,mm
str=str.replace(/ [*·x] *([0-9]+) *(.*)/, " ($2)$1")
str=str.replace(/\(/g,"+(").replace(/([0-9]+)/g,"*$1")
if (!str.match(/[A-Z]/)) str=str.toUpperCase()
for (i=0; i<amass.length;i++) { str=str.replace(amass[i][0],amass[i][1]) }
try {mm=eval(str)} catch (foo) {mm=-1}
return [str,mm]
}
Die erste komische Substitution regelt Fälle wie "CuSO4 ⋅ 5 H2O", das ist für Dich vermutlich nicht so wichtig. Dann wird es spannend:
- In der zweiten Zeile wird vor jede Zahl ein "*" geschrieben, der dient später als Multiplikationszeichen. Aus dem Input "Na3PO4" wird also "Na*3PO*4".
- Die nächste Zeile kopiert auf Uppercase falls alles Lowercase ist, das ist nur eine Eingabehilfe, damit man statt V(CO)6 einfach v(co)6 schreiben kann.
- In der for-Schleife wird dann die Textsubstitution durchgeführt. Aus "Na*3PO*4" entsteht schrittweise "+22.9897*2SO*4", danach "+22.9897*2S+15.9994*4" und schließlich "+22.9897*2+32.065+15.9994*4"
- Zuletzt wird mit eval ausgeführt — falls die Ausführung nicht klappt, war die Summenformel nicht wohlgeformt, und über einen exception-Handler wird in diesem Fall der Wert −1 für die molare Masse zugewiesen.
ich würde den String der Formel von hinten "anknabbern", denn dann kommen die Kleinbuchstaben von Zwei-Zeichen-Elementen (z.B. Na) zuerst. Dann ist klar, dass man noch ein Zeichen braucht, um das Element zu identifizieren.
Zudem brauchst du eine Tabelle mit den Elementsymbolen und deren Massen.
Kannst ja eine KI einen Vorschlag machen lassen...
Mit dem list()-Befehl können Sie die Eingabe direkt in die einzelnen Symbole zerlegen. Hier einmal für Methanol gezeigt:
Ich würde das so angehen, dass ich ein "Suchfenster" aus z. B. zwei Variablen n1 und n2 erstelle und dieses dann über die Liste der einzelnen Elemente schiebe.
Wenn n2 keine Zahl ist, dann liegt das Element in n1 einfach vor; wenn n2 eine Zahl ist, dann muss sich diese Zahl natürlich auf das Element in n1 beziehen. Dann berechnen Sie einfach die entsprechende Masse des Elements (gegebenenfalls mit der Zahl multiplizieren) und fügen es einem Speicher hinzu. Anschließend das Suchfenster solange weiter verschieben, bis n1 wieder ein Elementsymbol (d.h. keine Zahl enthält) und der Zyklus kann von vorne beginnen.
Dieser recht grobschlächtige Ansatz funktioniert natürlich nur, wenn in der Eingabe Elementsymbole mit nur einem Buchstaben (C, N, O usw.) und keine "Sonderzeichen" (x, ., (, [ usw.) enthalten sind. Für Summenformeln, die Klammern enthalten oder Zahlen größer als 9, muss man dann entsprechende Anpassungen treffen.

funktioniert natürlich nur, wenn in der Eingabe Elementsymbole mit nur einem Buchstaben (C, N, O usw.)
Das ist schon eine sehr heftige Einschränkung.