PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Chemische Formeln


Auf der Mauer
03.09.2012, 12:14:52
Hallo Experten,

ich habe ein Problem, bei dem ich nicht mehr alleine weiterkomme.
Aus Formeln möchte ich gerne automatisch alle chemischen Elemente extrahieren.
Das ganze quasi on the fly, also direkt bei der Ausgabe.


Bsp. Kochsalz
NaCl -> Natrium, Chlorid

Bsp. Wasser
H2O -> Wasserstoff, Sauerstoff

Mein bisher erarbeiteter Code enthält noch ein dickes Problem.

Es gibt z.B. das Element Schwefel (Kürzel = S) und es gibt Silizium (Kürzel = Si).
Bei der jetzigen Umwandlung wird jeder Fund von Si zu Schwefel während das i lose überbleibt.
Na klar, woher soll die Anwendung auch wissen, wo die Blöcke getrennt werden müssen.

Hier ist mal mein Quelltext:


/*
Chemische Elemente aus einem Formelstring auslesen und die
Kurzschreibweise durch ganze Worte ersetzen. Anschließend
das Ergebnis alphabetisch sortieren.
*/

// Prüfen, ob das Formular überhaupt abgeschickt wurde
if (isset($_POST['submit']) && $_POST['submit'] == 'los') {

// Array mit Kürzeln
$arr = array('Ca','As','Ba', 'S', 'Si');

// Array mit Wörtern
$arr2 = array('Kalzium, ', 'Arsen, ', 'Barium, ', 'Schwefel, ', 'Silizium, ');


// Alles außer Buchstaben aus dem Formelstring entfernen
$element_str = preg_replace("/[^a-zA-Z]/","",$_POST['formula']);

// Kürzel durch Wörter ersetzen
$element_str = str_replace($arr, $arr2, $element_str);


// Ausgabe zur Kontrolle
echo "<p>" . $element_str . "</p>";

}


Das Formular zum Testen


<!-- FORMULUAR FÜR CHEMISCHE FORMEL ////////////////////////////////////////////// -->

<form name="formula" method="post" action="/test.php">
<input name="formula" size="50" type="text">
<input name="submit" type="submit" value="los">
</form>


Gibt man in das Formular z.B. Ca<sub>2</sub>As<sub>3</sub> ein wird folgerichtig Kalzium, Arsen ausgegeben.
Bei Si für Silizium wird aber Schwefel angezeigt.

Ich bin für jeden Tipp dankbar!

Gruß
Auf der Mauer

vt1816
03.09.2012, 14:37:47
Hallo,

einen Versuch wäre es Wert, die Werte im Array (Kürzel) absteigend nach Anzahl der Buchstaben zu sortieren (Uuo, Uus, ..., Si, Pb, ..., S, O, H, ...). In Ermangelung einer Testumgebung kann ich es hier zzt. nicht testen.

Jedoch was passiert bei Verbindungen aus einbuchstabigen Elementen (H & F) für die es ein anderes Element gibt (Hf - Hafnium)?

Auf der Mauer
03.09.2012, 14:48:13
Hallo vt1816,

danke für die Antwort.
Mit der Sortierung werde ich es mal ausprobieren.

Ja bei deinem Beispiel ist es ja dasselbe Problem wie beim Schwefel und dem
Silizium. Da ich nicht alle Elemente brauche, kommt Hafnium zwar nicht in mein Array,
funktionieren sollte es aber natürlich trotzdem.

Gruß
Auf der Mauer

Auf der Mauer
03.09.2012, 14:55:11
Hallo,

leider funktioniert es mit der Sortierung nicht. Das Ergebnis ist dasselbe.


// Array mit allen Chemischen Elementen + Namen

$elements = array ( "Ag"=>"Silber", "Al"=>"Aluminium", "Au"=>"Gold",
"As"=>"Arsen", "Ba"=>"Barium", "Bi"=>"Wismut",
"C"=>"Kohlenstoff", "Ca"=>"Kalzium", "Cd"=>"Cadmium",
"Cl"=>"Chlor", "Co"=>"Kobalt", "Cu"=>"Kupfer",
"Fe"=>"Eisen", "Ge"=>"Germanium", "H"=>"Wasserstoff",
"Hg"=>"Quecksilber", "K"=>"Kalium", "Mg"=>"Magnesium",
"Mn"=>"Mangan", "N"=>"Stickstoff", "Na"=>"Natrium",
"Ni"=>"Nickel", "O"=>"Sauerstoff", "P"=>"Phosphor",
"Pb"=>"Blei", "S"=>"Schwefel", "Sb"=>"Antimon",
"Si"=>"Silizium", "Sn"=>"Zinn", "Ti"=>"Titan",
"Zn"=>"Zink", "Zr"=>"Zirkonium",
);


Gibt es vielleicht eine Möglichkeit das fertige Array dafür zu benutzen?
Hier sind alle in Frage kommenden Elemente drin.
Im Grunde stimmen doch Teile aus dem Formularstring mit dem Arrayschlüssel überein.
Da müßte ja dann der zugehörige Wert rausgeholt werden.

Gruß
Auf der Mauer

vt1816
03.09.2012, 15:35:09
Die ganze Sache wird - wie jetzt aufgebaut - nicht funktionieren. Siehe Dir dazu mal das Beispiel #2 Beispiele möglicher str_replace() Überraschungen (http://de.php.net/str_replace) an.

Besonderes Verhalten bei der Reihenfolge der Ersetzungen

Weil str_ireplace() von links nach rechts ersetzt, kann sie einen zuvor eingesetzten Wert ersetzen, falls mehrere Ersetzungen durchgeführrt werden. Beispiel #2 in der Dokomenation von str_replace() zeigt, wie dies sie in der Praxis betreffen kann.


Dann sollte es Dir klarer werden. Du erhältst durch die Elementen mit nur einem Buchstaben immer eine Übersetzung - selbst in schon "übersetzten" Elementen. Immer in der Abhängigkeit der Schreibweise in Deinem Array (Wasserstoff -> Waserstoff, aber WasserStoff -> WasserSchwefel, toff, Schwefel, auerstoff, )


Si -> Schwefel, i
H2O -> Wasserstoff, Schwefel, auerstoff,


Da musst Du wohl noch mal Deine Problemstellung/Aufgabe überdenken.

Auf der Mauer
03.09.2012, 17:42:09
Mhh ja, das ist irgendwie Käse.
Stichprobenartig mit den richtigen Elementen getestet dachte ich schon ich wäre fertig. ;)

Viele Wege führen nach Rom.

Vermutlich kann es nicht schaden den Formelstring erstmal nach bestimmten Regeln zu Gruppieren. Hier würde helfen die Werte immer paarweise einzulesen, denn Kürzel sind maximal 2 Zeichen lang. Doppelte Vorkommen im String müssen eh noch entfernt werden.

Na dann werde ich mich mal daran setzen.
Bin aber nach wie vor für Tipps dankbar!

Gruß
Auf der Mauer

Auf der Mauer
03.09.2012, 18:30:54
Ich glaube ich habe es. ;)


// Array mit allen Chemischen Elementen + Namen

$elements = array ( "Ag"=>"Silber", "Al"=>"Aluminium", "Au"=>"Gold",
"As"=>"Arsen", "Ba"=>"Barium", "Bi"=>"Wismut",
"C"=>"Kohlenstoff", "Ca"=>"Kalzium", "Cd"=>"Cadmium",
"Cl"=>"Chlor", "Co"=>"Kobalt", "Cu"=>"Kupfer",
"Fe"=>"Eisen", "Ge"=>"Germanium", "H"=>"Wasserstoff",
"Hg"=>"Quecksilber", "K"=>"Kalium", "Mg"=>"Magnesium",
"Mn"=>"Mangan", "N"=>"Stickstoff", "Na"=>"Natrium",
"Ni"=>"Nickel", "O"=>"Sauerstoff", "P"=>"Phosphor",
"Pb"=>"Blei", "S"=>"Schwefel", "Sb"=>"Antimon",
"Si"=>"Silizium", "Sn"=>"Zinn", "Ti"=>"Titan",
"Zn"=>"Zink", "Zr"=>"Zirkonium",
);


// Prüfen, ob das Formular überhaupt abgeschickt wurde
if (isset($_POST['submit']) && $_POST['submit'] == 'los') {

// Alle Zeichen außer Buchstaben aus String entfernen
$element_str = preg_replace("/[^a-zA-Z]/","",$_POST['formula']);

echo "<p>" . strtr($element_str, $elements) . "</p>";

}




<!-- FORMULUAR FÜR CHEMISCHE FORMEL ////////////////////////////////////////////// -->

<form name="formula" method="post" action="/test.php">
<input name="formula" size="50" type="text">
<input name="submit" type="submit" value="los">
</form>


Gruß
Auf der Mauer

Ckaos
03.09.2012, 23:20:03
Hi

Ich glaube ich habe es. ;)
sieht nach ner guten Lösung aus.
Doppelte Vorkommen im String müssen eh noch entfernt werden.
Vielleicht könnte man den ausgetauschten ein komma mit übergeben um dann nach
komma aufzulösen und wiederum ein array zu generieren um doppelte auszuschliessen.
Bsp.
<!-- FORMULUAR FÜR CHEMISCHE FORMEL ////////////////////////////////////////////// -->

<form name="formula" method="post" action="" enctype="multipart/form-data">
<input name="formula" size="50" type="text">
<input name="submit" type="submit" value="los">
</form>
<?php
// Array mit allen Chemischen Elementen + Namen

$elements = array ( "Ag"=>"Silber,", "Al"=>"Aluminium,", "Au"=>"Gold,",
"As"=>"Arsen,", "Ba"=>"Barium,", "Bi"=>"Wismut,",
"C"=>"Kohlenstoff,", "Ca"=>"Kalzium,", "Cd"=>"Cadmium,",
"Cl"=>"Chlor,", "Co"=>"Kobalt,", "Cu"=>"Kupfer,",
"Fe"=>"Eisen,", "Ge"=>"Germanium,", "H"=>"Wasserstoff,",
"Hg"=>"Quecksilber,", "K"=>"Kalium,", "Mg"=>"Magnesium,",
"Mn"=>"Mangan,", "N"=>"Stickstoff,", "Na"=>"Natrium,",
"Ni"=>"Nickel,", "O"=>"Sauerstoff,", "P"=>"Phosphor,",
"Pb"=>"Blei,", "S"=>"Schwefel,", "Sb"=>"Antimon,",
"Si"=>"Silizium,", "Sn"=>"Zinn,", "Ti"=>"Titan,",
"Zn"=>"Zink,", "Zr"=>"Zirkonium,"
);


// Prüfen, ob das Formular überhaupt abgeschickt wurde
if (isset($_POST['submit']) && isset($_POST['formula']) && $_POST['formula']>'') {

// Alle Zeichen außer Buchstaben aus String entfernen
$element_str = preg_replace("/[^a-zA-Z]/","",$_POST['formula']);

// Kürzel in Namen wandeln
$replaced_string = strtr($element_str, $elements);

// String in Array wandeln
$str2array = preg_split('/[,]+/', $replaced_string, NULL, PREG_SPLIT_NO_EMPTY);
// Jeder Wert nur einmal
$result = array_unique($str2array);
// Ausgabe
echo "<p>" . implode(',',$result) . "</p>";

}

mfg

CKaos

vt1816
04.09.2012, 14:24:38
Auch dieser Code klappt nur, solange man sich an die Groß- und Kleinschreibung der Elemente hält.

Beispiel: Natriumchlorid (Kochsalz) - NaCl

NaCl -> Natrium,Chlor

NACL -> Stickstoff,AKohlenstoff,L
NaCL -> Natrium,Kohlenstoff,L
NACl -> Stickstoff,AChlor

Auf der Mauer
04.09.2012, 15:45:20
Hallo CKaos,

danke für die Antwort.
Ich habe eine Zeile von dir verwendet, ich hoffe es ist in Ordnung.


// <sub> und <sup> Tags entfernen
$element_str = strip_tags($_POST['formula']);

// Alle Zeichen außer Buchstaben entfernen
$element_str = preg_replace("/[^a-zA-Z]/","",$element_str);

// Kürzel durch ganze Wörter ersetzen
$element_str = strtr($element_str, $elements);

// Doppelte Einträge aus String entfernen
$element_str = implode(' ', array_unique(explode(' ', $element_str)));

// String in Array umwandeln
$array = preg_split('/[,]+/', $element_str, NULL, PREG_SPLIT_NO_EMPTY);

// Array alphabetisch sortieren
sort($array);

// Ergebnis anzeigen
foreach ($array as $value) {
echo $value . "<br> \n ";
}


Soweit so gut, das sieht doch schon sehr ordentlich aus.
Allerdings gibt es bei der Arraysortierung noch ein Problem.

Die chemische Formel

CuPb<sub>4</sub>O<sub>2</sub>SO<sub>4</sub>(OH)<sub>4</sub>H<sub>2</sub>O

ergibt

Blei
Sauerstoff
Schwefel
Wasserstoff
Kupfer

Das Element Kupfer steht warum auch immer an der falschen Stelle.

Gruß
Auf der Mauer

Auf der Mauer
04.09.2012, 15:49:21
Auch dieser Code klappt nur, solange man sich an die Groß- und Kleinschreibung der Elemente hält.

Beispiel: Natriumchlorid (Kochsalz) - NaCl

NaCl -> Natrium,Chlor

NACL -> Stickstoff,AKohlenstoff,L
NaCL -> Natrium,Kohlenstoff,L
NACl -> Stickstoff,AChlor

Hallo,

ja aber so wären sie ja auch falsch geschrieben. NaCl wird genauso geschrieben.
Alles andere ist falsch.

Die Formeln werden eh mit fertigen Bausteinen zusammengebaut, da bleibt kein Raum für Falschangaben.
Du klickst z.B. auf Natrium und Na wird automatisch eingefügt.
So sind Fehler eigentlich ausgeschlossen, da ja nichts manuell eingegeben wird.

Gruß
Auf der Mauer

vt1816
04.09.2012, 16:15:09
[...]
Du klickst z.B. auf Natrium und Na wird automatisch eingefügt.
So sind Fehler eigentlich ausgeschlossen, da ja nichts manuell eingegeben wird.

Gruß
Auf der Mauer

Wozu benötigst Du dann ein/das Formular?

Auf der Mauer
04.09.2012, 16:36:37
Das Formular war nur zum testen hier gedacht, so konnte jeder der Spaß daran hatte es gleich mal ausprobieren.

Die Formel kommt stattdessen aus einer Datenbank.
Jetzt wird sie vollautomatisch in ihre Komponenten zerlegt.
Es war mir einfach zu mühselig bei jeder Formel das von Hand anzugeben.

Die Sortierung stimmt jetzt auch, ich habe einfach das Komma als Flag entfernt.


$array = preg_split('/[ ]+/', $element_str, NULL, PREG_SPLIT_NO_EMPTY);


Gruß
Auf der Mauer

Ckaos
04.09.2012, 20:47:03
Hi

Ich habe eine Zeile von dir verwendet, ich hoffe es ist in Ordnung.
Sind zwar 3 zu einer gemacht aber egal, natürlich war ja für dich und alle die es lesen.
$element_str = implode(' ', array_unique(explode(' ', $element_str)));
Ich empfehle dir so nicht Codezeilen zu sparen das wird schnell unübersichtlich.
Ausserdem schreibst du dann wenn du eins davon zu einem späteren Codepunkt
brauchst wieder um oder neu.
Die Sortierung stimmt jetzt auch, ich habe einfach das Komma als Flag entfernt.
Du weist aber schon warum das Komma da war?

mfg

CKaos

Auf der Mauer
04.09.2012, 21:31:52
Ja danke für den Tipp, man soll ja nicht am falschen Ende sparen. ;)

Ich denke doch dass das Komma als Trenner dienen solllte, um aus den einzelnen Stringeinträgen Arrayelemente zu machen. Das geht jetzt ohne Komma aber auch,
da alle Werte in dem String durch ein Leerzeichen getrennt sind.

Nach der Anwendung der Sortierfunktion kam aber eine falsche Reihenfolge heraus.
Jetzt funktionierte es aber einwandfrei.

Gruß
Auf der Mauer