用Excel计算分子量

Rya*_*n_C 2 excel vba excel-vba excel-formula

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

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

例如," 乙腈 " 的分子量在列中列为:C2H3N.

我想要做的是编写一个扫描该单元格内容的函数,然后说:"好的,每当我遇到文本的内容时,请查看紧随其后的数字,直到找到另一个文本然后停止.然后,取这个数字乘以特定元素的分子量"(我将在以后处理分子量的总和因为我觉得这是容易的部分).

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

小智 5

虽然通过一些使用本机Excel函数的非常复杂(和CPU密集型)公式可以轻微地执行您的请求,但VBA 用户定义函数UDF将更加合适.我不是化学家,所以请原谅我提供的单个样本,因为它们是从网页上无耻地偷走的.TBH,我甚至不确定我的一半术语是否正确.

     有机化合物原子量

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

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

     具有分子量的周期表

在名为Element Data的工作表上,转到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
Run Code Online (Sandbox Code Playgroud)

只有第一个与您发布的问题相关.后两者使用Unicode下标字符对化合物的化学式进行样式化并反转过程.

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

= udf_Molecular_Weight(<纯文本中具有复合公式的单个单元格>)

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

=udf_Molecular_Weight(B2)

... 要么,

=udf_Molecular_Weight("C2H3N")

有9000+这些,我怀疑你会使用前一种方法.必要时填写.虽然这个UDF比使用其他原生工作表函数的复杂数组公式更有效INDIRECT,但它们并不神奇.在提交到9000+之前测试几百行的公式,这样您就知道会发生什么.如果你选择使用它们,另外两个UDF的工作方式大致相同.

正如所承诺的,这里是我为此目的创建的示例.XLSB工作簿的链接,供您下载和参考.

    Chemical_Compound_Atomic_Weights.xlsb

该链接将保持活跃一段时间.如果我将其位置更改为更长久的存储空间,我将在此处调整链接.

简要说明:

通过'变量声明',我猜你实际上意味着'变量赋值'.我倾向于编写相当紧密的代码,并且通过使用冒号堆叠变量的归零,我已经将其他人将最多4个代码行放入单行中的内容.我转过来,

sTMP = sCMPND
dAWEIGHT = 0
sSB = "0"
sEL = vbNullString
Run Code Online (Sandbox Code Playgroud)

......进入这个,

sTMP = sCMPND: dAWEIGHT = 0: sSB = "0": sEL = vbNullString
Run Code Online (Sandbox Code Playgroud)

IT行业有史以来最严重的错误之一是会计师决定向程序员支付他们编写的每一行代码.

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

这两个Do While ... Loop字符串遍历通过字符传递给函数字符串的字符串.内循环专门处理数字.每次通过循环都会截断左边的字符串,将其缩短一个或多个字符,并将这些字符收集为元素的符号或与其在有机化合物中使用相关的数字.最终有什么可以截断(长度= 0),这是其中CBool(Len(sTMP))成为并结束循环.内循环的执行方式大致相同,但收集数字直到达不到长度或字母字符.在收集了元素(和可能的数字修饰剂)之后,化合物中该元素VLOOKUP的分子量用针对分子量表计算并加入到越来越多的数字中.当所有元素及其相关数字已被收集并添加到总计中时,总计将作为该函数的结果返回.