【问题标题】:sub(): Handling of backreferencessub():反向引用的处理
【发布时间】:2011-08-10 14:30:48
【问题描述】:

假设我有一个像“C5Cl2NO2S”这样的分子式,我想在 R 中计算其分子量。我虽然最简单的方法是使用正则表达式,分析公式并将其拆分为元素组件,然后将它们交给执行计算的单独函数。但是,我面临的问题是,当我交出我的 RegEx 的反向引用时,它们不会被评估而是以“\\1”、“\\2”的形式提交。

这是我的尝试:

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"
)

任何想法如何改善这一点? 非常感谢

【问题讨论】:

    标签: regex r


    【解决方案1】:

    下面我们假设问题中的公式形式,即一串组件,每个组件都是一个大写字母,后跟可选的小写字母,后跟可选的数字。我们在 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
    

    【讨论】:

      【解决方案2】:

      我不认为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
      

      【讨论】:

      • 我想和你一样+1
      • 感谢您的解决方案。对于我的情况,您的限制完全可以。基本上你把它带到了重点:我需要一个函数,它给我匹配的组作为返回值。我终于用unlist( strsplit( sub( ..., replacement="\\1#\\2\\#3\\4# ... ", ... ), split="#" ) ) 找到了我的解决方案。不是很优雅,但很高效:-)
      【解决方案3】:

      【讨论】:

      • 感谢您的链接,但不幸的是,它们都与我的问题无关。分子式只是我今天研究的主题,但我的问题是在 R 中处理 RegEx 的反向引用。
      • 哎呀。对于那个很抱歉。我将把问题留在这里,因为其他人可能会偶然发现这个问题,寻找那些:)
      【解决方案4】:

      看看

      RSiteSearch ("molecular weight")
      

      我猜第 2 次或第 3 次命中就是您要寻找的(第一次是蛋白质)。

      (抱歉,没有看到您对另一个答案的评论 - 但是,我留下这个以防有人真的在寻找分子量计算)。

      【讨论】:

      • 这只是我今天问题的完美解决方案!
      猜你喜欢
      • 2016-09-18
      • 2017-11-13
      • 2010-11-25
      • 2014-07-28
      • 2017-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-30
      相关资源
      最近更新 更多