这是我的尝试:
masses <- list(
C = 12,
H = 1.01,
Cl = 34.97,
N = 14.00,
O = 15.99,
P = 30.97,
S = 31.97
)
elementMass <- function( element, count ) {
if( count == "" ) {
count <- "1"
}
return( as.character( masses[[ element ]] * as.numeric( count ) ) )
}
sumFormula2Mass <- function( x ){
y <- 0.0
for( e in x ) {
if( e != "" ) {
y <- y + as.numeric( sub( "^(C|H|Cl|N|O|P|S)([0-9]*)$", elementMass("\\1", "\\2"), e ) )
}
}
return( y )
}
sub(
"^(C[0-9]*)?(H[0-9]*)?(Cl[0-9]*)?(N[0-9]*)?(O[0-9]*)?(P[0-9]*)?(S[0-9]*)?$",
sumFormula2Mass( c("\\1", "\\2", "\\3", "\\4", "\\5", "\\6", "\\7") ),
"C5Cl2NO2S"
)
任何想法如何改善这一点? 非常感谢
答案 0 :(得分:5)
下面我们假设问题中的公式形式,即一串组件,每个组件都是大写字母,后面可选地跟小写字母,后跟可选的数字。我们在gsubfn包中使用gsubfn
。它类似gsub
,但替换字符串可以是各种其他对象。这是一个原型对象。 proto对象是一个环境,此处用于包含属性sum
和两个方法pre
和fun
。在开始时,pre会自动运行,并具有初始化sum
的效果。然后,每次正则表达式匹配时,proto对象和两个引用的字符串将传递给fun
,并运行fun
来处理它们。最后p$sum
包含结果。变量masses
在问题中定义。
library(gsubfn)
p <- proto(pre = function(this) this$sum <- 0,
fun = function(this, name, count) {
count <- as.numeric(count)
if (is.na(count)) count <- 1
this$sum <- this$sum + masses[[name]] * count
""
})
gsubfn("([[:upper:]][[:lower:]]*)(\\d*)", p, "C5Cl2NO2S")
p$sum # 207.89
答案 1 :(得分:3)
我认为sub()
中的反向引用并不像这样。您似乎将它们视为返回值,当它们是输入时。
这是一个不同的解决方案。它需要一种非常不同的方法,即将字符串分成单独的部分,然后参考这些。但是,它有一些局限性。首先,它假定不能用括号处理化学式。其次,它假定原子是合理写入的(即氯写成Cl - 大写C和小写l)。可能存在许多其他限制,但这应该让您了解此解决方案的外观。
sumFormula2Mass2 <- function(x,masses){
summedMasses <- NULL
for(e in x){
## split up the string
split.e <- unlist(strsplit(e,''))
## join letters from individual elements (since subequent letters should be lower case)
ilower <- grep('[a-z]',split.e)
if(length(ilower) > 0){
for(i in 1:length(ilower)){
j <- ilower[i]
split.e <- c(if(j > 2) split.e[1:(j-2)],
paste(split.e[(j-1):j],collapse=''),
if(j < length(split.e)) split.e[(j+1):length(split.e)])
ilower <- ilower - 1
}
}
## join numbers together (in case there are more than 10 atoms)
inum <- grep('[0-9]',split.e)
if(length(inum) > 1){
for(i in 1:(length(inum)-1)){
if(inum[i + 1] == inum[i] + 1){
j <- inum[i]
split.e <- c(split.e[1:(j-1)],
paste(split.e[j:(j+1)],collapse=''),
if(j+2 <= length(split.e)) split.e[(j+2):length(split.e)])
inum <- inum - 1
}
}
}
## add up the mass
sumMass = 0
for(i in 1:length(split.e)){
if(length(grep('[1-9]',split.e[i])) > 0){
next
} else if(split.e[i] %in% names(masses)){
nMolecules <- 1
if(i != length(split.e) && length(grep('[1-9]',split.e[i+1])) > 0)
nMolecules <- as.numeric(split.e[i+1])
sumMass <- sumMass + nMolecules * masses[[split.e[i]]]
} else {
warning(sprintf('Could not match element %s',split.e[i]))
next
}
}
summedMasses <- c(summedMasses,sumMass)
}
return(summedMasses)
}
以下是您的化合物加上一些化妆品(我不是化学家)的一些结果:
> sumFormula2Mass2(c("C5Cl2NO2S","C5Cl2NO2S4","C5Cl10NO2S4"),masses)
[1] 207.89 303.80 583.56
答案 2 :(得分:0)
信不信由你,这似乎不是那么罕见:
http://www.sitepoint.com/forums/php-34/chemical-formula-regular-expressions-317012.html
我通过Google搜索molecular formula regex
答案 3 :(得分:0)
看看
RSiteSearch ("molecular weight")
我想第二次或第三次命中是你正在寻找的(第一种是蛋白质)。
(抱歉,没有看到你对另一个答案的评论 - 但是,如果有人真的在寻找分子量计算,我会留下这个。)