我目前正在开发一个可以解析化学式并返回分子量和组成百分比的程序。以下代码适用于 H2O、LiOH、CaCO3 甚至 C12H22< 等化合物/sub>O11。但是,它无法理解括号内包含多原子 ionic 的化合物,例如 (NH4)2SO4。
我并不是要找人来为我编写程序,而只是给我一些关于如何完成这样的任务的提示。
目前,程序遍历输入的字符串,raw_molecule
,首先找到每个元素的原子序数,存储在一个 vector 中(我使用 map<string, int>
来存储名称和原子编号)。然后找到每个元素的数量。
bool Compound::parseString() {
map<string,int>::const_iterator search;
string s_temp;
int i_temp;
for (int i=0; i<=raw_molecule.length(); i++) {
if ((isupper(raw_molecule[i]))&&(i==0))
s_temp=raw_molecule[i];
else if(isupper(raw_molecule[i])&&(i!=0)) {
// New element- so, convert s_temp to atomic # then store in v_Elements
search=ATOMIC_NUMBER.find (s_temp);
if (search==ATOMIC_NUMBER.end())
return false;// There is a problem
else
v_Elements.push_back(search->second); // Add atomic number into vector
s_temp=raw_molecule[i]; // Replace temp with the new element
}
else if(islower(raw_molecule[i]))
s_temp+=raw_molecule[i]; // E.g. N+=a which means temp=="Na"
else
continue; // It is a number/parentheses or something
}
// Whatever's in temp must be converted to atomic number and stored in vector
search=ATOMIC_NUMBER.find (s_temp);
if (search==ATOMIC_NUMBER.end())
return false;// There is a problem
else
v_Elements.push_back(search->second); // Add atomic number into vector
// --- Find quantities next --- //
for (int i=0; i<=raw_molecule.length(); i++) {
if (isdigit(raw_molecule[i])) {
if (toInt(raw_molecule[i])==0)
return false;
else if (isdigit(raw_molecule[i+1])) {
if (isdigit(raw_molecule[i+2])) {
i_temp=(toInt(raw_molecule[i])*100)+(toInt(raw_molecule[i+1])*10)+toInt(raw_molecule[i+2]);
v_Quantities.push_back(i_temp);
}
else {
i_temp=(toInt(raw_molecule[i])*10)+toInt(raw_molecule[i+1]);
v_Quantities.push_back(i_temp);
}
}
else if(!isdigit(raw_molecule[i-1])) { // Look back to make sure the digit is not part of a larger number
v_Quantities.push_back(toInt(raw_molecule[i])); // This will not work for polyatomic ions
}
}
else if(i<(raw_molecule.length()-1)) {
if (isupper(raw_molecule[i+1])) {
v_Quantities.push_back(1);
}
}
// If there is no number, there is only 1 atom. Between O and N for example: O is upper, N is upper, O has 1.
else if(i==(raw_molecule.length()-1)) {
if (isalpha(raw_molecule[i]))
v_Quantities.push_back(1);
}
}
return true;
}
这是我的第一篇文章,所以如果我包含的信息太少(或太多),请原谅我。
最佳答案
虽然您可以做一个类似扫描器的临时操作来处理一个级别的括号,但用于此类操作的规范技术是编写一个真正的解析器。
有两种常用的方法...
- Recursive descent
- 基于语法规范文件的机器生成的自下而上解析器。
(从技术上讲,还有第三类,PEG,即机器生成的自上而下。)
无论如何,对于情况 1,当您看到 (
时,您需要编写对解析器的递归调用,然后从 )
token 。
通常会创建一个树状的内部表示;这称为语法树,但在您的情况下,您可能可以跳过它并仅从递归调用返回原子量,添加到您将从第一个实例返回的级别。
对于情况 2,您需要使用像 yacc 这样的工具 将语法转换为解析器。
关于c++ - 化学式解析器 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9957939/