【发布时间】:2022-01-16 07:43:21
【问题描述】:
我在电子表格中有数千个化学式的列表,我想计算每个化学元素在每个化学式中出现的次数。这里给出了一些例子:
- CH3NO3
- CSe2
- C2Cl2
- C2Cl2O2
- C4H6COOH
- (C6H5)2P(CH2)6P(C6H5)2
我发现@PEH (Extract numbers from chemical formula) 的一些代码运行良好。但是,在提取数千个值时会变得非常慢。因此,我创建了一个数组版本(见下文),并设法通过其他用户的一些输入来加快速度(How to speed up extracting numbers from chemical formula)。它有效并且确实加快了速度。但是,我还需要它在括号内找到多个元素(下面的代码目前不适用于上面的化学式 6 - 应该是 30 C、32 H、2 P)。我希望有人能够提出一种基于下面的正则表达式方法来实现这一目标的方法。原始 ChemRegex 中有一些代码可以执行此操作(https://stackoverflow.com/a/46091904/17194644),但我无法使其在子中工作 - 如果我尝试将其包含在子中,则会出现此错误:
Private RegEx As RegExp
Function CountElements(ChemFormulaRange As Variant, ElementRange As Variant) As Variant
'define variables
Dim RetValRange() As Long
Dim RetVal As Long
Dim ChemFormula As String
Dim npoints As Long
Dim i As Long
Dim mpoints As Long
Dim j As Long
' Connvert input ranges to variant arrays
If TypeName(ChemFormulaRange) = "Range" Then ChemFormulaRange = ChemFormulaRange.Value
If TypeName(ElementRange) = "Range" Then ElementRange = ElementRange.Value
'parameter
npoints = UBound(ChemFormulaRange, 1) - LBound(ChemFormulaRange, 1) + 1
mpoints = UBound(ElementRange, 2) - LBound(ElementRange, 2) + 1
'dimension array
ReDim RetValRange(1 To npoints, 1 To mpoints)
If RegEx Is Nothing Then
Set RegEx = New RegExp
' apply the properties
End If
'calculate all values
For j = 1 To mpoints
Element = ElementRange(1, j)
For i = 1 To npoints
RetVal = 0
ChemFormula = ChemFormulaRange(i, 1)
Call ChemRegex(ChemFormula, Element, RetVal, RegEx)
RetValRange(i, j) = RetVal
Next i
Next j
'output answer
CountElements = RetValRange
End Function
Private Sub ChemRegex(ChemFormula, Element, RetVal, RegEx)
'ChemRegex created by PEH (CC BY-SA 4.0) https://stackoverflow.com/a/46091904/17194644
With RegEx
.Global = True
.MultiLine = True
.IgnoreCase = False
End With
'first pattern matches every element once
RegEx.Pattern = "([A][cglmrstu]|[B][aehikr]?|[C][adeflmnorsu]?|[D][bsy]|[E][rsu]|[F][elmr]?|[G][ade]|[H][efgos]?|[I][nr]?|[K][r]?|[L][airuv]|[M][cdgnot]|[N][abdehiop]?|[O][gs]?|[P][abdmortu]?|[R][abefghnu]|[S][bcegimnr]?|[T][abcehilms]|[U]|[V]|[W]|[X][e]|[Y][b]?|[Z][nr])([0-9]*)"
Dim Matches As MatchCollection
Set Matches = RegEx.Execute(ChemFormula)
Dim m As Match
For Each m In Matches
If m.SubMatches(0) = Element Then
RetVal = RetVal + IIf(Not m.SubMatches(1) = vbNullString, m.SubMatches(1), 1)
End If
Next m
End Sub
【问题讨论】:
-
将 1000 的原始电子表格拆分为多张,每张 1000。然后复制粘贴特殊值并组合结果。
-
被调用的函数 (ChemRegEx) 看起来需要四个参数(ChemFormula、Element、RetVal、RegEx),但您只提供了前两个参数,这将引发您看到的错误。
-
这个问题归结为调试您对
ChemRegEx的调用。剩下的就是噪音。我建议编辑 Q 以专注于此,包括指向函数源的链接,然后删除其余部分。顺便说一句,bugdrown 已经为您提供了您需要知道的内容 -
我已经回答了一个关于在 PHP 中展平/扩展化学方程式的类似问题,这可能对简单的括号公式有用:stackoverflow.com/a/20672549/406712