代码之家  ›  专栏  ›  技术社区  ›  slhck

无法使用强制引入的R取消序列化YAML列:NAs超出实际范围:3.0

  •  0
  • slhck  · 技术社区  · 8 年前

    我正在R上使用版本为2.1.15的yaml包,试图将web应用程序从yaml生成的列反序列化为JSON格式。

    > tbl %>%
    +   select(value) %>% 
    +   collect() %>% 
    +   head(20)
    # A tibble: 20 x 1
                                                                           value
                                                                           <chr>
     1                                                                "--- []\n"
     2                                                                "--- []\n"
     3                     "---\n- - unknown\n  - 383.0\n- - hd720\n  - 425.0\n"
     4                                                                "--- []\n"
     5                                             "---\n- - hd720\n  - 102.0\n"
     6                                             "---\n- - unknown\n  - 0.0\n"
     7                                                                "--- []\n"
     8                      "---\n- - unknown\n  - 301.0\n- - hd1080\n  - 1.0\n"
     9                                                                "--- []\n"
    10                                           "---\n- - hd1080\n  - 1103.0\n"
    11                                                                "--- []\n"
    12                                                                "--- []\n"
    13                                            "---\n- - hd1080\n  - 803.0\n"
    14                                             "---\n- - hd720\n  - 143.0\n"
    15                                                                "--- []\n"
    16                                                                "--- []\n"
    17 "---\n- - unknown\n  - 9.0\n- - hd1080\n  - 102.0\n- - hd720\n  - 37.0\n"
    18                                           "---\n- - unknown\n  - 136.0\n"
    19                                             "---\n- - hd720\n  - 973.0\n"
    20                      "---\n- - unknown\n  - 330.0\n- - hd1080\n  - 3.0\n"
    

    我尝试使用以下函数取消序列化此列:

    df = read.csv("test.txt")
    df %>% 
      rowwise() %>% 
      mutate(
        unserialized_value = ifelse(
          is.recursive(yaml.load(value)) || is.vector(yaml.load(value)),
          as.character(toJSON(yaml.load(value))),
          as.character(yaml.load(value)))
      ) %>%
      View()
    

    我实现了相同的函数:

    unserialize_value <- function(val) {
      if (length(val) != 1) {
        stop("unserialize_value input must be of length 1")
      }
      if (is.na(val)) {
        return(NA)
      } else {
        print(paste("orig val:", val))
        yaml_val = yaml.load(val)
        print(paste("YAML val:", yaml_val))
        if (is.recursive(yaml_val) || is.vector(yaml_val)) {
          print("returning list")
          return(as.character(toJSON(yaml_val)))
        } else {
          print("returning char")
          return(as.character(yaml_val))
        }
      }
    }
    

    在中使用此功能时 mutate (但也在使用内联代码时),我得到如下输出(调试语句):

    [1] "returning list"
    [1] "orig val: ---\n- - hd720\n  - 973.0\n"
    [1] "YAML val: list(\"hd720\", NA)"
    [1] "returning list"
    [1] "orig val: ---\n- - unknown\n  - 330.0\n- - hd1080\n  - 3.0\n"
    [1] "YAML val: list(\"unknown\", NA)" "YAML val: list(\"hd1080\", NA)"
    

    事实上,这些数字已经变成 NA s、 由于这些错误:

    1: In yaml.load(value) : NAs introduced by coercion: 301.0 is out of real range
    2: In yaml.load(value) : NAs introduced by coercion: 1.0 is out of real range
    3: In yaml.load(value) : NAs introduced by coercion: 301.0 is out of 
    ...
    

    文件位于此处: test.txt

    有趣的是,当我这样做的时候:

    toJSON(yaml.load("---\n- - unknown\n  - 330.0\n- - hd1080\n  - 3.0\n"))
    

    工作正常:

    [[["unknown"],[330]],[["hd1080"],[3]]]
    

    有什么事情发生在 dplyr / 变异 打电话把转换搞砸了?

    2 回复  |  直到 8 年前
        1
  •  0
  •   user96622    8 年前

    我刚刚运行了你的代码,它在所有情况下都运行良好。我怀疑加载的库中存在版本差异。请包括sessionInfo()输出以进行比较。

    这是我的:

    > sessionInfo()
    R version 3.4.3 (2017-11-30)
    Platform: x86_64-pc-linux-gnu (64-bit)
    Running under: Ubuntu 16.04 LTS
    
    Matrix products: default
    BLAS: /usr/lib/openblas-base/libblas.so.3
    LAPACK: /usr/lib/libopenblasp-r0.2.18.so
    
    locale:
     [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
     [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
     [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
    
    attached base packages:
    [1] stats     graphics  grDevices utils     datasets  methods   base     
    
    other attached packages:
    [1] bindrcpp_0.2 dplyr_0.7.4  magrittr_1.5 yaml_2.1.15  jsonlite_1.5
    
    loaded via a namespace (and not attached):
     [1] compiler_3.4.3   assertthat_0.2.0 R6_2.2.2         tools_3.4.3      glue_1.2.0       tibble_1.3.4    
     [7] Rcpp_0.12.13     pkgconfig_2.0.1  rlang_0.1.2      bindr_0.1  
    

    ==== 更新后,该漏洞已在最新版本的r-yaml中修复。根本原因是在转换时检查错误号时出现了其他错误。由于这是c stdlib中的一个共享全局函数,因此可以通过使用c stdlib的任何东西来设置它,在本例中,它是使用数字零上的log10的jsonlite。此设置为errno,稍后在转换时被检测为错误。解决方案是在r-yaml包中使用strtol或strtoi之前清除errno。

    TL;DR从CRAN安装最新的r-yaml。

        2
  •  0
  •   slhck    8 年前

    这是YAML包的一个bug, fixed in the most recent release .