Pregunta

Estoy tratando de escribir un método para una aplicación que tome una fórmula química como "CH3COOH" y devuelve algún tipo de colección llena de sus símbolos.

Ch3Cooh regresaría [C, H, H, H, C, O, O, H

Ya tengo algo que funciona un poco, pero es muy complicado y usa mucho código con muchas estructuras y bucles if-else anidados.

¿Hay alguna manera de hacer esto usando algún tipo de expresión regular con String.split o tal vez en algún otro código simple brillante?

¿Fue útil?

Solución

Suponiendo que está en mayúscula correctamente, cada símbolo en la ecuación coincide con esta expresión regular:

[A-Z][a-z]*\d*

(Para los desafiados químicamente, el símbolo de un elemento siempre es una letra mayúscula seguida de opcionalmente una minúscula o posiblemente dos, por ejemplo, Hg para mercurio)

Puede capturar el símbolo del elemento y el número en grupos como así:

([A-Z][a-z]*)(\d*)

Entonces sí, en teoría, esto sería algo con lo que las expresiones regulares podrían ayudar. Si estás tratando con fórmulas como C6H2(NO2)3(CH3)3 Entonces tu trabajo es, por supuesto, un poco más difícil ...

Otros consejos

He desarrollado un par de series de artículos sobre cómo analizar fórmulas moleculares, incluidas fórmulas más complejas como C6H2 (NO2) 3CH3.

La más reciente es mi presentación "Many y pyparsing"En Pycon2010, donde comparo esos dos sistemas de análisis de pitón utilizando un evaluador de fórmula molecular como mi problema de muestra. Incluso hay un Video de mi presentación.

La presentación se basó en un serie de artículos de tres partes Desarrollé un analizador de fórmula molecular usando ANTLR. En parte 3 Comparo la solución ANTLR con un analizador y soluciones de expresión regular escrita a mano en capas y pyParsing.

Las soluciones regexp y caply se desarrollaron por primera vez en un serie de dos partes sobre dos formas de escribir analizadores en Python.

La solución regexp y las soluciones base antlr/sly/pyParsing, use una expresión regular como [AZ] [AZ]? D* para que coincidan con los términos en la fórmula. Esto es lo que @David M sugirió.

Aquí está funcionando en Python

import re

# element_name is: capital letter followed by optional lower-case
# count is: empty string (so the count is 1), or a set of digits
element_pat = re.compile("([A-Z][a-z]?)(\d*)")

all_elements = []
for (element_name, count) in element_pat.findall("CH3COOH"):
    if count == "":
        count = 1
    else:
        count = int(count)
    all_elements.extend([element_name] * count)

print all_elements

Cuando ejecuto esto (es codificado para usar ácido acético, CH3COOH) que obtengo

['C', 'H', 'H', 'H', 'C', 'O', 'O', 'H']

Tenga en cuenta que este breve bit de código supone que la fórmula molecular es correcta. Si le da algo como "## $%^o2#$$#", entonces ignorará los campos que no conoce y le dará ['O', 'O']. Si no quieres eso, tendrás que hacerlo un poco más robusto.

Si desea admitir fórmulas más complicadas, como C6H2 (NO2) 3CH3, entonces necesitará saber un poco sobre las estructuras de datos de los árboles, específicamente (como señala @Roman), árboles de sintaxis abstractos (con la mayor frecuencia llamados AST). Eso es demasiado complicado para entrar aquí, así que vea mi charla y ensayos para obtener más detalles.

La solución con expresiones regulares es el mejor enfoque si necesita manejar solo casos simples. De lo contrario, necesitas construir algo como Árbol de sintaxis abstracta y evaluarlo o usar Notación polaca.

Por ejemplo, fórmula TNT C6H2(NO2)3CH3 debe presentarse como:

(+ (* C 6) (* H 2) (* (+ N (* O 2)) 3) C (+ H 3))

¿Ha buscado expresar sus fórmulas químicas en Lenguaje de marcado químico? Es muy versátil y hay muchas herramientas/espectadores que pueden representar estas foro o compuestos químicos en 2D a 3D.

Estoy trabajando en un programa que requiere cálculos de masa molar de fórmulas químicas, por lo que he creado una solución con la que funciona para una variedad de fórmulas.

Por ejemplo, "(CH3) 16 (TC (H2O) 3CO (BRFE3 (RECL) 3 (SO4) 2) 2) 2MNO4" dará como resultado "16C 48H 2TC 12H 6O 2C 2O 4BR 12FE 12RE 12CL 8S 32O MN 4O" (( Este complejo está hecho, pero bueno, ¡funciona!)

Este código está escrito en C#, por eso no lo he publicado. Si estás interesado, puedo publicarlo para ti. De hecho, escribí una respuesta completa antes de notar la etiqueta Java.

De todos modos, funciona básicamente agrupando bloques de átomos coincidentes con paréntesis recursivamente. No maneja coeficientes como 2PB (pero (PB) 2 o PB2 funciona) o compuestos cargados como OH-.

De ninguna manera es simple o elegante. Quería una solución de funcionamiento, así que sé que hay mejores maneras (¡ni siquiera probé expresiones regulares!). Pero funciona con las fórmulas que necesito, tal vez también se adapte a las tuyas.

Aquí hay algunos casos de prueba en los que lo ejecuto. Eche un vistazo a ellos y avíseme si el código C# aún sería útil para usted. El formato es (entrada, salida esperada)

        ("Pb ", " Pb"); 
        ("H ", " H"); 
        ("Pb2 ", " 2Pb"); 
        ("H2 ", " 2H");             
        ("3Pb2 ", " 6Pb");
        ("Pb2SO4", " 2Pb S 4O");                                     
        ("PbH2 ", " Pb 2H");            
        ("(PbH2)2 ", " 2Pb 4H");
        ("(CCC)2 ", " 2C 2C 2C");
        ("Pb(H2)2 ", " Pb 4H");            
        ("(Pb(H2)2)2 ", " 2Pb 8H"); 
        ("(Pb(H2)2)2NO3 ", " 2Pb 8H N 3O"); 
        ("(Ag(Pb(H2)2)2)2SO4 ", " 2Ag 4Pb 16H S 4O");             
        ("Pb(CH3(CH2)2CH3)2", " Pb 2C 6H 4C 8H 2C 6H"); 
        ("Na2(CH3(CH2)2CH3)2", " 2Na 2C 6H 4C 8H 2C 6H");
        ("Tc(H2O)3Fe3(SO4)2", " Tc 6H 3O 3Fe 2S 8O");
        ("Tc(H2O)3(Fe3(SO4)2)2", " Tc 6H 3O 6Fe 4S 16O");
        ("(Tc(H2O)3(Fe3(SO4)2)2)2", " 2Tc 12H 6O 12Fe 8S 32O");
        ("(Tc(H2O)3CO(Fe3(SO4)2)2)2", " 2Tc 12H 6O 2C 2O 12Fe 8S 32O");
        ("(Tc(H2O)3CO(BrFe3(ReCl)3(SO4)2)2)2MnO4", " 2Tc 12H 6O 2C 2O 4Br 12Fe 12Re 12Cl 8S 32O Mn 4O");
        ("(CH3)16(Tc(H2O)3CO(BrFe3(ReCl)3(SO4)2)2)2MnO4", " 16C 48H 2Tc 12H 6O 2C 2O 4Br 12Fe 12Re 12Cl 8S 32O Mn 4O"); 
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top