【问题标题】:Test for numeric elements in a character string测试字符串中的数字元素
【发布时间】:2012-11-18 06:28:51
【问题描述】:

我想测试一个字符串,看看哪些元素实际上可能是数字。我可以使用正则表达式来测试整数是否成功,但我希望查看哪些元素具有所有数字和 1 个或更少的小数。以下是我尝试过的:

x <- c("0.33", ".1", "3", "123", "2.3.3", "1.2r")
!grepl("[^0-9]", x)   #integer test

grepl("[^0-9[\\.{0,1}]]", x)  # I know it's wrong but don't know what to do

我正在寻找一个逻辑输出,所以我希望得到以下结果:

[1] TRUE TRUE TRUE TRUE FALSE FALSE

【问题讨论】:

  • 怎么样 !is.na(as.numeric(x)) ?编辑:哦,我看到有人回答了这个问题,因为我正在仔细检查它是否适用于您的示例(在按“添加评论”之前检查它是否按要求工作)
  • 我刚刚意识到字符串中可能已经有 NA。
  • 如果你也想区分 NA,试试这个:ifelse(is.na(x), NA, TRUE) &amp; is.na(as.numeric(x))

标签: regex r


【解决方案1】:

也许您的其他一些数据更复杂会破坏这一点,但我的第一个想法是:

> !is.na(as.numeric(x))
[1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE

正如下面 Josh O'Brien 所指出的,这不会提取像 7L 这样的东西,R 解释器会将其解析为整数 7。如果您需要将它们包含为“似是而非的数字”,则一种方法是先用正则表达式把它们挑出来,

x <- c("1.2","1e4","1.2.3","5L")
> x
[1] "1.2"   "1e4"   "1.2.3" "5L"   
> grepl("^[[:digit:]]+L",x)
[1] FALSE FALSE FALSE  TRUE

...然后使用gsub 和索引从这些元素中去除“L”。

【讨论】:

  • 它的简单性。杰出的。 :尴尬:
  • @joran - 是否有不输出警告的替代方法,或者最好的办法是将其包装在suppressWarnings 中并继续使用它?
  • @Joran 如果字符串中已经有 NA 怎么办?没关系使用:!is.na(as.numeric(na.omit(x))) 在这种情况下,这将有效,但可能不适用于其他未来的搜索者。
  • @TylerRinker 有什么问题? NA 应该仍然给出 FALSE 不是吗?这不是你想要的结果吗?
  • @thelatemail 我不知道。我认为suppressWarnings 可能是要走的路。
【解决方案2】:

我最近遇到了一个类似的问题,我试图编写一个函数来格式化从另一个函数作为字符串传递的值。格式化后的值最终会出现在表格中,我想创建逻辑来识别 NA、字符串和数字的字符表示,以便在生成表格之前对它们应用 sprintf()

虽然阅读起来更复杂,但我确实喜欢 grepl() 方法的稳健性。我认为这得到了 cmets 中提出的所有示例。

x <- c("0",37,"42","-5","-2.3","1.36e4","4L","La","ti","da",NA)

y <- grepl("[-]?[0-9]+[.]?[0-9]*|[-]?[0-9]+[L]?|[-]?[0-9]+[.]?[0-9]*[eE][0-9]+",x)

这将被评估为(格式化以帮助可视化):

x
[1] "0"  "37"   "42"  "-5"   "-2.3"   "1.36e4" "4L" "La"     "ti"     "da"     NA 

y
[1] TRUE  TRUE   TRUE  TRUE   TRUE     TRUE    TRUE FALSE   FALSE    FALSE    FALSE

正则表达式为真:

  • 不超过一位小数的正数或负数或
  • 正整数或负整数(例如 4L)或
  • 科学计数法中的正数或负数

如果数据集包含格式不佳的数字,则可以添加其他术语来处理没有前导数字的小数或带有小数点但小数点后的数字。

【讨论】:

  • 很棒的一个。为我工作。
【解决方案3】:

避免使用 varhandle 包中的 check.numeric() 重新发明轮子。

该函数接受以下参数:

v 字符向量或因子向量。 (强制)

na.rm 合乎逻辑。该函数是否应该忽略 NA?默认值为 FLASE 因为 NA 可以转换为数字。 (可选)

only.integer 合乎逻辑。只检查整数,不接受 浮点。默认值为假。 (可选)

exceptions 包含字符串的字符向量 被认为是有效的转换为数字。 (可选)

ignore.whitespace 合乎逻辑。忽略前导和尾随空格 评估向量是否可以转换为数字之前的字符。 默认值为 TRUE。 (可选)

【讨论】:

    【解决方案4】:

    另一种可能性:

    x <- c("0.33", ".1", "3", "123", "2.3.3", "1.2r", "1.2", "1e4", "1.2.3", "5L", ".22", -3)
    locs <- sapply(x, function(n) {
    
        out <- try(eval(parse(text = n)), silent = TRUE)
        !inherits(out, 'try-error')
    
    }, USE.NAMES = FALSE)
    
    x[locs]
    ## [1] "0.33" ".1"   "3"    "123"  "1.2"  "1e4"  "5L"   ".22"  "-3"  
    
    x[!locs]
    ## [1] "2.3.3" "1.2r"  "1.2.3"
    

    【讨论】:

      【解决方案5】:

      受此处答案的启发,我的函数修剪了前导和尾随空格,可以处理 na.strings,并且可以选择将 NA 视为数字。正则表达式也得到了增强。有关详细信息,请参阅帮助信息。随心所欲!

      check if a str obj is actually numeric
      @description check if a str obj is actually numeric
      #' @param x a str vector, or a factor of str vector, or numeric vector. x will be coerced and trimws.
      #' @param na.strings case sensitive strings that will be treated to NA.
      #' @param naAsTrue whether NA (including actual NA and na.strings) will be treated as numeric like
      #' @return a logical vector (vectorized).
      #' @export
      #' @note Using regular expression
      #' \cr TRUE for any actual numeric c(3,4,5,9.9) or c("-3","+4.4",   "-42","4L","9L",   "1.36e4","1.36E4",    NA, "NA", "","NaN", NaN): 
      #' \cr positive or negative numbers with no more than one decimal c("-3","+4.4") OR
      #' \cr positive or negative integers (e.g., c("-42","4L","39L")) OR
      #' \cr positive or negative numbers in scientific notation c("1.36e4","1.36E4")
      #' \cr NA, or na.strings
      is.numeric.like <- function(x,naAsTrue=TRUE,na.strings=c('','.','NA','na','N/A','n/a','NaN','nan')){
          x = trimws(x,'both')
          x[x %in% na.strings] = NA
          # https://stackoverflow.com/a/21154566/2292993
          result = grepl("^[\\-\\+]?[0-9]+[\\.]?[0-9]*$|^[\\-\\+]?[0-9]+[L]?$|^[\\-\\+]?[0-9]+[\\.]?[0-9]*[eE][0-9]+$",x,perl=TRUE)
          if (naAsTrue) result = result | is.na(x)
          return((result))
      }
      

      【讨论】:

        【解决方案6】:

        你也可以使用:

        readr::parse_number("I am 4526dfkljvdljkvvkv")
        

        得到 4526。

        【讨论】:

        • 这会从字符串中提取数字,但不检查字符串是否实际上是数字
        猜你喜欢
        • 2019-08-30
        • 2013-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-13
        • 2021-01-27
        相关资源
        最近更新 更多