【问题标题】:Calculating Molecular Weight Using Excel使用 Excel 计算分子量
【发布时间】:2014-11-20 22:40:54
【问题描述】:

我在这里遇到了一些问题。我有一个包含大约 9,000 种有机化合物的电子表格,我正在尝试计算所有这些化合物的分子量。

通常,这很容易:只需将分子式中的元素数量乘以元素的分子量,然后将它们全部相加即可。问题是,电子表格将分子式列为字符串。

例如,“乙腈”的分子量在列中列为:C2H3N

我想做的是编写一个函数来扫描该单元格的内容并说:“好的,每次我遇到文本时,请查看紧随其后的数字,直到您点击另一个文本并且然后停止。然后,用那个数字乘以那个特定元素的分子量”(稍后我会处理分子量的总和,因为我觉得这很容易)。

这可能与 Excel 的内置函数有关,还是我必须使用 VBA(我真的没有经验)。在这里的任何帮助将不胜感激。

【问题讨论】:

  • 是的,我发现了类似的东西,但它并没有完全回答我的问题。
  • 我会四处寻找。如果我找不到一个好的方法,我可能只需要暴力破解所有 9,000 列。就我而言,我需要“C”进入它自己的列,“2”进入它自己的列,“H”进入它自己的列等等。到目前为止,什么都没有。
  • 因此,如果您可以创建一个权重字典(一个名称列表,由 :'s 到值分隔),我已经完成了一些与此非常相似的模块。当然是在 VBA 中。
  • @Ryan_C 上传一个范围有限的演示文件,清楚地说明您的单元格格式以及元素的摩尔重量存储在哪里?
  • @pnuts,你可能在想这个:stackoverflow.com/questions/26358179/…

标签: excel excel-formula vba


【解决方案1】:

虽然您的请求可以通过一些非常复杂(且 CPU 密集型)公式仅使用原生 Excel 函数来实现,但 VBA 用户定义函数UDF 将非常有用更合适。我不是化学家,所以请原谅我提供的对您的单个样品的添加,因为它们是从Internet page 无耻地偷走的。 TBH,我什至不确定我是否有一半的术语正确。

     

第 1 步 - 创建一个分子量表并命名

您将需要某种形式的交叉引用来从元素的周期符号中检索分子量。这是我拼凑的。我将在下面的示例工作簿中提供指向完整数据表的链接。

     

在名为元素数据的工作表上,转到Formulas ► Defined Names ► Name Manger 并为交叉引用矩阵指定一个定义的名称。

     

在这里,我使用了一个公式 (=OFFSET('Element Data'!$A$1,0,0,COUNTA( 'Element Data'!$A:$A),6)) 来定义范围,但数据的大小是相当静态的,因此单元格范围引用应该绰绰有余。

第 2 步 - 添加用户定义函数的代码

点击Alt+F11,当VBE打开时,立即使用下拉菜单Insert ► Module (Alt+I+M)。将以下内容粘贴到标题为 Book1 - Module1 (Code) 的新窗格中。

Public Function udf_Molecular_Weight(sCMPND As String) As Double
    Dim sTMP As String, i As Long, sEL As String, sSB As String
    Dim dAW As Double, dAWEIGHT As Double, dSUB As Long
    sTMP = sCMPND: dAWEIGHT = 0: sSB = "0": sEL = vbNullString
    Do While CBool(Len(sTMP))
        sSB = "0": sEL = vbNullString
        If Asc(Mid(sTMP, Application.Min(2, Len(sTMP)), 1)) > 96 Then
            sEL = Left(sTMP, 2)
        Else
            sEL = Left(sTMP, 1)
        End If
        sTMP = Right(sTMP, Len(sTMP) - Len(sEL))
        Do While IsNumeric(Left(sTMP, 1))
            sSB = sSB & Int(Left(sTMP, 1))
            sTMP = Right(sTMP, Len(sTMP) - 1)
        Loop
        'Debug.Print sEL & ":" & (Int(sSB) - (Not CBool(Int(sSB))))
        dAWEIGHT = dAWEIGHT + Application.VLookup(sEL, ThisWorkbook.Names("tblPeriodic").RefersToRange, 6, False) * (Int(sSB) - (Not CBool(Int(sSB))))
    Loop
    udf_Molecular_Weight = dAWEIGHT
End Function

Public Function udf_Styled_Formula_Alt(sCMPND As String) As String
    Dim sb As Long, sCOMPOUND As String
    sCOMPOUND = sCMPND
    For sb = 0 To 9
        sCOMPOUND = Replace(sCOMPOUND, sb, ChrW(8320 + sb))
    Next sb
    udf_Styled_Formula_Alt = sCOMPOUND
End Function

Public Function udf_Unstyled_Formula_Alt(sCMPND As String) As String
    Dim sb As Long, sCOMPOUND As String
    sCOMPOUND = sCMPND
    For sb = 0 To 9
        sCOMPOUND = Replace(sCOMPOUND, ChrW(8320 + sb), sb)
    Next sb
    udf_Unstyled_Formula_Alt = sCOMPOUND
End Function

只有第一个与您发布的问题相关。后两者风格化化合物的化学式用Unicode下标字符并逆向处理。

完成粘贴后,点击 Alt+Q 返回工作表。这些 UDF 函数现在可以在您的工作簿中使用,就像任何本机 Excel 函数一样。语法尽可能简单。

=udf_Molecular_Weight()

对于您的示例化合物(在上面的数据图像中),这将是,

=udf_Molecular_Weight(B2)

...或者,

=udf_Molecular_Weight("C2H3N")

其中有 9000 多个,我怀疑您会使用前一种方法。根据需要填写。虽然这个 UDF 比使用 INDIRECT 和其他本机工作表函数的复杂 array 公式要高效得多,但它们并不神奇。在提交到 9000+ 之前,在几百行上测试公式,这样你就知道会发生什么。如果您选择使用其他两个 UDF,它们的工作方式大致相同。

简要说明:

'变量声明',我猜你实际上是指'变量赋值'。我倾向于编写相当紧凑的代码,并且通过将变量的归零与冒号堆叠在一起,我将其他人最多可以放入 4 行代码行中的内容放在一行中。我转这个,

sTMP = sCMPND
dAWEIGHT = 0
sSB = "0"
sEL = vbNullString

...进入这个,

sTMP = sCMPND: dAWEIGHT = 0: sSB = "0": sEL = vbNullString

在重新进入循环之前需要重置变量,但这是一项平凡的任务,所以我只是将所有四个分配都塞进一行。

两个Do While ... Loop逐个字符地爬取传入函数的字符串。内部循环专门处理数字。每次通过循环都会从左侧截断字符串,将其缩短一个或多个字符,并将这些字符收集为元素的符号或与其在有机化合物中的使用相关的数字。最终没有任何东西可以截断(长度=0),这就是CBool(Len(sTMP)) 变为 False 并且循环结束的地方。内部循环的执行方式大致相同,但会收集数字直到它没有长度或字母字符。在收集到一个元素(和可能的数字修饰符)后,化合物中该元素的分子量使用VLOOKUP 对照分子量表计算,并添加到一个不断增长的数字中。当所有元素及其相关数量已收集并添加到总计中时,总计将作为函数的结果返回。

【讨论】:

  • 能否对这段代码做更多解释?出于显而易见的原因,我不想简单地复制和粘贴您的代码。我很难理解这里的变量声明以及“Do While”循环中发生的事情。能否提供一些额外的解释?
  • @Ryan_C - 我添加了一些关于上述过程背后的机制的杂谈。
  • 我想我更多的意思是你定义的这些变量代表什么。例如 sTMP = sCMPD: daWEIGHT = O: sSB = 0: sEL = vbNullString。
  • 这行得通,除了这一行:Application.VLookup 需要是 Application.WorksheetFunction.VLookup。此外 - 如果分子组中有括号,例如在 Ca(OH)2 中,则此方法不起作用。
【解决方案2】:

@Jeeped 有一个很棒的 VBA 解决方案。我在 How to count up elements in excel 上发布了针对相关问题的非 VBA 解决方案。很容易扩展到这个问题。

将每个元素放在一个单独的列中,其原子质量在其上方。

这个公式将计算分子中每个原子的重量:

=B$1*
 MAX(IFERROR(IF(FIND(B$2&ROW($2:$100),$A3),ROW($2:$100),0),0),
     IFERROR(IF(FIND(B$2&CHAR(ROW($66:$91)),$A3&"Z"),1,0),0)
 )

作为数组公式输入:Ctrl + Shift + Enter

总分子量将是重量的总和。

示例:

【讨论】:

    猜你喜欢
    • 2019-11-17
    • 2020-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多