formatR代碼自動化排版

前言

程序員最痛苦的事情,不是每天加班寫程序,而是每天加班讀懂別人寫的程序。

大多數程序員寫的代碼都沒有考慮,如何讓別人看著更方便!最後,實在忍受不了看其他人的醜陋代碼時,有人開始制定代碼編程規範;又有人實現代碼的自動化排版工具。formatR就是這樣的一個R語言自動化排版的工具。

目錄

  1. formatR介紹
  2. formatR安裝
  3. formatR的API介紹
  4. formatR的使用
  5. formatR的源代碼解析

1. formatR介紹

formatR包是一個實用的包,提供了R代碼格式化功能,自動設置空格、縮進、換行等代碼格式,讓代碼看起來更友好。

formatR的發布頁:formatR - Yihui Xie | 謝益輝

2. formatR安裝

系統環境

  • Win7 64bit
  • R: 3.0.1 x86_64-w64-mingw32/x64 b4bit

formatR安裝

~ R> install.packages("formatR")trying URL http://mirror.bjtu.edu.cn/cran/bin/windows/contrib/3.0/formatR_0.10.zipContent type application/zip length 49263 bytes (48 Kb)opened URLdownloaded 48 Kbpackage 『formatR』 successfully unpacked and MD5 sums checked

formatR載入

library(formatR)

3. formatR的API介紹

  • 1). tidy.source: 對代碼進行格式化
  • 2). tidy.eval: 輸出格式化的R代碼和運行結果
  • 3). usage: 格式化函數定義,並按指定寬度輸出
  • 4). tidy.gui: 一個GUI工具,支持編輯並格式化R代碼
  • 5). tidy.dir: 對某個目錄下,所有R腳本進行格式化

3. formatR的使用

  • 1). tidy.source:以字元串形式,對代碼格式化
  • 2). tidy.source:以文件形式,對代碼格式化
  • 3). 格式化並輸出R腳本文件
  • 4). tidy.eval: 輸出格式化的R代碼和運行結果
  • 5). usage: 格式化函數定義,並按指定寬度輸出
  • 6). tidy.gui: GUI工具,編輯並格式化R代碼
  • 7). tidy.dir: 對目錄下,所有R腳本進行格式化

1). 以字元串形式,對代碼格式化

> tidy.source(text = c("{if(TRUE)1 else 2; if(FALSE){1+1", "## comments", "} else 2}")){if (TRUE) 1 else 2if (FALSE) {1 + 1## comments } else 2}

2). 以文件形式,對代碼格式化

> messy = system.file("format", "messy.R", package = "formatR")> messy[1] "C:/Program Files/R/R-3.0.1/library/formatR/format/messy.R"

原始代碼輸出

> src = readLines(messy)> cat(src,sep="
")# a single line of comments is preserved1+1if(TRUE){x=1 # inline comments}else{x=2;print(Oh no... ask the right bracket to go away!)}1*3 # one space before this comment will become two!2+2+2 # short commentslm(y~x1+x2, data=data.frame(y=rnorm(100),x1=rnorm(100),x2=rnorm(100))) ### only single quotes are allowed in comments1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1 ## comments after a long linea character string with in it## here is a long long long long long long long long long long long long long long long long long long long long comment

格式化後的代碼輸出

> tidy.source(messy)# a single line of comments is preserved1 + 1if (TRUE) { x = 1 # inline comments} else { x = 2print("Oh no... ask the right bracket to go away!")}1 * 3 # one space before this comment will become two!2 + 2 + 2 # short commentslm(y ~ x1 + x2, data = data.frame(y = rnorm(100), x1 = rnorm(100), x2 = rnorm(100))) ### only single quotes are allowed in comments1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 ## comments after a long line"a character string with in it"## here is a long long long long long long long long long long long long long long long long## long long long long comment

3). 格式化並輸出R腳本文件

新建R腳本文件:demo.r

~ vi demo.ra<-1+1;a;matrix(rnorm(10),5);if(a>2) { b=c(11,832);"#a>2";} else print(a is invalid!!)

格式化demo.r

> x = "demo.r"> tidy.source(x)a <- 1 + 1amatrix(rnorm(10), 5)if (a > 2) { b = c("11", 832)"#a>2"} else print("a is invalid!!")

輸出格式化結果到文件:demo2.r

> f="demo2.r"> tidy.source(x, keep.blank.line = TRUE, file = f)> file.show(f)

4). tidy.eval: 輸出格式化的R代碼和運行結果

以字元串形式,執行R腳本

> tidy.eval(text = c("a<-1+1;a", "matrix(rnorm(10),5)"))a <- 1 + 1a## [1] 2matrix(rnorm(10), 5)## [,1] [,2]## [1,] 0.65050729 0.1725221## [2,] 0.05174598 0.3434398## [3,] -0.91056310 0.1138733## [4,] 0.18131010 -0.7286614## [5,] 0.40811952 1.8288346

5). usage: 格式化函數定義,並按指定寬度輸出

> varfunction (x, y = NULL, na.rm = FALSE, use){if (missing(use))use <- if (na.rm)"na.or.complete"else "everything"na.method <- pmatch(use, c("all.obs", "complete.obs", "pairwise.complete.obs","everything", "na.or.complete"))if (is.na(na.method))stop("invalid use argument")if (is.data.frame(x))x <- as.matrix(x)else stopifnot(is.atomic(x))if (is.data.frame(y))y <- as.matrix(y)else stopifnot(is.atomic(y)).Call(C_cov, x, y, na.method, FALSE)}<bytecode: 0x0000000008fad030><environment: namespace:stats>> usage(var)var(x, y = NULL, na.rm = FALSE, use)

usage函數,只輸出函數的定義。

> usage(lm,width_=30)lm(formula, data, subset, weights, na.action, method = "qr", model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, contrasts = NULL, offset, ...)

usage的width參數,控制函數的顯示寬度。

6). tidy.gui: GUI工具,編輯並格式化R代碼

安裝gWidgetsRGtk2庫

> install.packages("gWidgetsRGtk2")also installing the dependencies 『RGtk2』, 『gWidgets』trying URL http://mirror.bjtu.edu.cn/cran/bin/windows/contrib/3.0/RGtk2_2.20.25.zipContent type application/zip length 13646817 bytes (13.0 Mb)opened URLdownloaded 13.0 Mbtrying URL http://mirror.bjtu.edu.cn/cran/bin/windows/contrib/3.0/gWidgets_0.0-52.zipContent type application/zip length 1212449 bytes (1.2 Mb)opened URLdownloaded 1.2 Mbtrying URL http://mirror.bjtu.edu.cn/cran/bin/windows/contrib/3.0/gWidgetsRGtk2_0.0-82.zipContent type application/zip length 787592 bytes (769 Kb)opened URLdownloaded 769 Kbpackage 『RGtk2』 successfully unpacked and MD5 sums checkedpackage 『gWidgets』 successfully unpacked and MD5 sums checkedpackage 『gWidgetsRGtk2』 successfully unpacked and MD5 sums checked

打開GUI控制台

> library("gWidgetsRGtk2")> g = tidy.gui()

我們輸入一段不太好看的代碼:

點擊「轉換」

在GUI的編輯器中,R語言的代碼被格式化了!

7). tidy.dir: 對dir目錄下,所有R腳本進行格式化

新建目錄:dir

新建兩個R腳本文件:dir.r, dir2.r

~ mkdir dir~ vi dir.ra<-1+1;a;matrix(rnorm(10),5);~ vi dir2.rif(a>2) { b=c(11,832);"#a>2";} else print(a is invalid!!)

執行tidy.dir

> tidy.dir(path="dir")tidying dir/dir.rtidying dir/dir2.r

分別查看dir.r和dir2.r

~ vi dir.ra <- 1 + 1amatrix(rnorm(10), 5) ~ vi dir2.rif (a > 2) { b = c("11", 832)"#a>2"} else print("a is invalid!!")

我們發現不規則的代碼,已經被格式化了!!

5. formatR的源代碼解析

通過上面的使用,我們不難發現formatR包的核心函數,就是tidy.source函數,從github上面找到源代碼:yihui/formatR

我將在代碼中增加註釋:

tidy.source = function( source = clipboard, keep.comment = getOption(keep.comment, TRUE), keep.blank.line = getOption(keep.blank.line, TRUE),replace.assign = getOption(replace.assign, FALSE),left.brace.newline = getOption(left.brace.newline, FALSE), reindent.spaces = getOption(reindent.spaces, 4),output = TRUE, text = NULL, width.cutoff = getOption(width), ...) { ## 判斷輸入來源為剪貼板if (is.null(text)) {if (source == clipboard && Sys.info()[sysname] == Darwin) {source = pipe(pbpaste) } } else { ## 判斷輸入來源為字元串source = textConnection(text); on.exit(close(source)) } ## 按行讀取來源數據 text = readLines(source, warn = FALSE) ## 大小處理 if (length(text) == 0L || all(grepl(^\s*$, text))) { if (output) cat(
, ...) return(list(text.tidy = text, text.mask = text)) } ## 空行處理 if (keep.blank.line && R3) { one = paste(text, collapse =
) # record how many line breaks before/after n1 = attr(regexpr(^
*, one), match.length) n2 = attr(regexpr(
*$, one), match.length) } ## 注釋處理 if (keep.comment) text = mask_comments(text, width.cutoff, keep.blank.line) ## 把輸入的R代碼,先轉成表達式,再轉回字元串。用來實現對每個語句的截取。 text.mask = tidy_block(text, width.cutoff, replace.assign && length(grep(=, text))) ## 對注釋排版text.tidy = if (keep.comment) unmask.source(text.mask) else text.mask ## 重新定位縮進text.tidy = reindent_lines(text.tidy, reindent.spaces) ## 擴號換行if (left.brace.newline) text.tidy = move_leftbrace(text.tidy) ## 增加首尾空行if (keep.blank.line && R3) text.tidy = c(rep(, n1), text.tidy, rep(, n2)) ## 在console列印格式化後的結果if (output) cat(paste(text.tidy, collapse =
),
, ...) ## 返回,但不列印結果invisible(list(text.tidy = text.tidy, text.mask = text.mask))}

Bug: 沒有對」->」進行處理

在讀源代碼的過程中,發現有一個小問題,沒有對」->」進行處理,已經給作者提bug了。

-> 符號處理的問題 · Issue #31 · yihui/formatR

bug測試代碼:

> c(11,832)->x2> x2[1] "11" "832"> tidy.source(text="c(11,832)->x2")c("11", 832) <- x2 > tidy.eval(text="c(11,832)->x2")c("11", 832) <- x2Error in eval(expr, envir, enclos) : object x2 not found

BUG已修復:

作者回復:這個問題已經在R 3.0.2中修正了。

> formatR::tidy.source(text="c(11,832)->x2")x2 <- c("11", 832) > sessionInfo()R version 3.0.2 (2013-09-25)Platform: x86_64-pc-linux-gnu (64-bit)locale: [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C [3] 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 [7] LC_PAPER=en_US.UTF-8 LC_NAME=C [9] LC_ADDRESS=C LC_TELEPHONE=C [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C attached base packages:[1] stats graphics grDevices utils datasets methods base loaded via a namespace (and not attached):[1] formatR_0.10.3

formatR包提供的功能非常實用,特別是讀別人寫的不規範的代碼的時候。建議各IDE廠商能把formatR,作為標準的格式化工具直接嵌入編輯器的工具裡面。讓我們把讀別人的代碼,也變成一件快樂的事情吧。

作者介紹:

民生銀行大數據中心數據分析師,前況客創始人兼CTO,10 年IT編程背景,獲得多項SUN及IBM技術認證。豐富的互聯網應用開發架構經驗,精通R ,Java, Nodejs 多種編程語言,掌握大數據處理,數據挖掘等核心技術,有統計和金融的知識積累。熟悉金融二級市場、交易規則和投研體系。多次在互聯網及數據分析大會中擔任演講嘉賓。著有《R的極客理想-工具篇》、《R的極客理想-高級開發篇》圖書,新書《R的極客理想-量化投資篇》(即將出版),博客粉絲日誌, Alexa全球排名70k。

博客專欄:張丹的博客專欄

大家也可以加小編微信:tswenqu(備註:知乎),進R語言中文社區 交流群,可以跟各位老師互相交流


推薦閱讀:

【機器學習】Bootstrap詳解
Kaggle比賽的終極武器: 模型融合(Model Ensemble)
一篇文章看懂數據挖掘,大數據,機器學習
【機器學習】如何做出一個更好的Machine Learning預測模型

TAG:R编程语言 | 数据挖掘 | 数据分析 |