Rの関数のhelpをcharacterとして取得する方法

表題のことがやりたくて,かなりさまよったのでメモ。

まず,help()は返り値としてhelp_files_with_topicクラスを吐く。invisible()で返すようになっているので,変数に付値しなければ見えない。

ただ,help_files_with_topicクラスの実体は関数のヘルプの位置を示したパスの文字列でしかなく,しかもRのヘルプは動的に生成されるので,パスの位置にファイルはない。そこで,help_files_with_topicクラスに対するprintメソッドを見てみたところ(getS3method("print", "help_files_with_topic")でみることができる),詳細がわかった。

> fun  <- "lm"
> file <- as.character(help(fun, help_type="text"))
> path <- dirname(file)
> dirpath <- dirname(path)
> pkgname <- basename(dirpath)
> RdDB <- file.path(path, pkgname)
> file
[1] "C:/PROGRA~2/R/R-210~1.1/library/stats/help/lm"
> path
[1] "C:/PROGRA~2/R/R-210~1.1/library/stats/help"
> pkgname
[1] "stats"
> RdDB
[1] "C:/PROGRA~2/R/R-210~1.1/library/stats/help/stats"
> temp <- tools::Rd2txt(tools:::fetchRdDB(RdDB, basename(file)), out = tempfile("Rtxt"), package = pkgname)
> h <- readLines(temp)

重要なのは最後から二行目だけ。toolsパッケージのRd2txt()で,Rdファイルから動的にテキストファイルを生成できる。outで出力するパスを指定し(今回は一時ファイルとして生成している),返り値としてパスを返す。Rd2txtのかわりにRd2HTMLを使うと,HTMLファイルを生成することができる。

下の関数は,helpをHTMLで取得して,argumentの部分だけ返す関数。XMLパッケージが必要です。

library(XML)

arghelp <- function(x, argname=NULL) {
  file <- as.character(help(x, help_type="text", try.all.packages=TRUE))
  path <- dirname(file)
  dirpath <- dirname(path)
  pkgname <- basename(dirpath)
  RdDB <- file.path(path, pkgname)
  if (file.exists(paste(RdDB, "rdx", sep = "."))) {
    temp <- tools::Rd2HTML(tools:::fetchRdDB(RdDB, basename(file)),
                           out = tempfile("Rtxt"), package = pkgname,
                           outputEncoding=localeToCharset()[1], no_links=TRUE)
    temp2 <- readLines(temp)
    temp2 <- gsub("(&lsquo;)|(&rsquo;)|(&ndash;)","", temp2)
    html <- htmlTreeParse(temp2, useInternalNodes=TRUE, error=xmlErrorCumulator(immediate=FALSE))
    file.remove(temp)
    argblock <- getNodeSet(html, "//table[@summary='R argblock']//td")
    argblock <- sapply(argblock, xmlValue)
    ind <- seq_len(length(argblock) / 2) * 2
    arg.value <- gsub("\n", "", argblock[ind])
    names(arg.value) <- argblock[ind - 1]
    if(is.null(argname)) argname <- names(arg.value)
    argname <- argname[!is.na(argname)]
    charmax <- max(nchar(argname)) + 1
    for( i in seq_along(argname)){
      cat(argname[i], paste(rep(" ", charmax - nchar(argname[i])), collapse=""))
      arg.tmp <- strsplit(arg.value[argname][i], " ")[[1]]
      len <- nchar(arg.tmp)
      arg.vec <- character()
      k <- 0
      l <- 1
      for(j in seq_along(arg.tmp)){
        k <- k + len[j]
        if (k > 60){
          arg.vec <- c(arg.vec, paste(arg.tmp[l:(j)], collapse=" "))
          k <- 0
          l <- j + 1
        }
      }
      arg.vec <- c(arg.vec, paste(arg.tmp[l:length(arg.tmp)], collapse=" "))
      cat(arg.vec[1], fill=TRUE)
      cat(paste(paste(rep(" ", charmax), collapse=""), arg.vec[-1], collapse="\n"), fill=TRUE)
      cat("\n")
    }
    return(invisible(arg.value[argname]))
  } else {
    return(NULL)
  }
}

HTMLの何が良いかというと,xpathでアクセスできること。かなりこれはかなり強力。

getNodeSet(html, "//table[@summary='R argblock']//td")というのがその部分にあたる。xpathについてはwikipedia等で。getNodeSetやxpathApplyを使うためには,HTMLをInternal形式(C-Level)で読み込む必要がある。これはxpathでのアクセスにlibxmlを使っているからだそうです。htmlTreeParse(x, useInternalNodes=TRUE)とかhtmlParse(x)とかしてやるとInternal形式で読み込める。

細かい部分では,htmlをparseする前のgsubの部分でかなりさ迷いました。XMLパッケージは認識できない実体参照があるとバグって変な文字コードを返すようです。今回はバグってた実体参照を消しただけ。

実行結果は以下のような感じ。helpを取得する属性を選択することもできる。返り値はinvisibleで文字列ベクトル。

> arghelp("cor")
x       a numeric vector, matrix or data frame.
        

y       NULL (default) or a vector, matrix or data frame withcompatible dimensions
        to x.   The default is equivalent toy = x (but more efficient).

na.rm   logical. Should missing values be removed?
        

use     an optional character string giving amethod for computing covariances
        in the presenceof missing values.  This must be (an abbreviation of) one of
        the strings"everything", "all.obs", "complete.obs","na.or.complete",
        or "pairwise.complete.obs".

method  a character string indicating which correlationcoefficient (or covariance)
        is to be computed.  One of"pearson" (default), "kendall", or "spearman",can
        be abbreviated.

V       symmetric numeric matrix, usually positive definite such as acovariance
        matrix.

> arghelp("cor", "use")
use  an optional character string giving amethod for computing covariances
     in the presenceof missing values.  This must be (an abbreviation of) one of
     the strings"everything", "all.obs", "complete.obs","na.or.complete",
     or "pairwise.complete.obs".

> arghelp("cor", c("use", "method"))
use     an optional character string giving amethod for computing covariances
        in the presenceof missing values.  This must be (an abbreviation of) one of
        the strings"everything", "all.obs", "complete.obs","na.or.complete",
        or "pairwise.complete.obs".

method  a character string indicating which correlationcoefficient (or covariance)
        is to be computed.  One of"pearson" (default), "kendall", or "spearman",can
        be abbreviated.