Jer*_*oen 9 regex r escaping gsub
要在json中编码字符串,需要使用反斜杠转义几个保留字符,并且每个字符串都需要用双引号括起来.目前,该jsonlite包使用deparse基R中的函数实现了这个:
deparse_vector <- function(x) {
stopifnot(is.character(x))
vapply(x, deparse, character(1), USE.NAMES=FALSE)
}
Run Code Online (Sandbox Code Playgroud)
这样做的诀窍:
test <- c("line\nline", "foo\\bar", "I said: \"hi!\"")
cat(deparse_vector(test))
Run Code Online (Sandbox Code Playgroud)
然而deparse,对于大型载体来说,结果却很慢.另一种实现是gsub单独为每个角色:
deparse_vector2 <- function(x) {
stopifnot(is.character(x))
if(!length(x)) return(x)
x <- gsub("\\", "\\\\", x, fixed=TRUE)
x <- gsub("\"", "\\\"", x, fixed=TRUE)
x <- gsub("\n", "\\n", x, fixed=TRUE)
x <- gsub("\r", "\\r", x, fixed=TRUE)
x <- gsub("\t", "\\t", x, fixed=TRUE)
x <- gsub("\b", "\\b", x, fixed=TRUE)
x <- gsub("\f", "\\f", x, fixed=TRUE)
paste0("\"", x, "\"")
}
Run Code Online (Sandbox Code Playgroud)
这有点快,但也不多,也有点难看.什么是更好的方法来做到这一点?(最好没有额外的依赖)
此脚本可用于比较实现:
> system.time(out1 <- deparse_vector1(strings))
user system elapsed
6.517 0.000 6.523
> system.time(out2 <- deparse_vector2(strings))
user system elapsed
1.194 0.000 1.194
Run Code Online (Sandbox Code Playgroud)
这是Winston代码的C++版本.它简单得多,因为你可以有效地发展std::string.它也不太可能崩溃,因为Rcpp会为你处理内存管理.
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
std::string escape_one(std::string x) {
std::string out = "\"";
int n = x.size();
for (int i = 0; i < n; ++i) {
char cur = x[i];
switch(cur) {
case '\\': out += "\\\\"; break;
case '"': out += "\\\""; break;
case '\n': out += "\\n"; break;
case '\r': out += "\\r"; break;
case '\t': out += "\\t"; break;
case '\b': out += "\\b"; break;
case '\f': out += "\\f"; break;
default: out += cur;
}
}
out += '"';
return out;
}
// [[Rcpp::export]]
CharacterVector escape_chars(CharacterVector x) {
int n = x.size();
CharacterVector out(n);
for (int i = 0; i < n; ++i) {
String cur = x[i];
out[i] = escape_one(cur);
}
return out;
}
Run Code Online (Sandbox Code Playgroud)
在您的基准测试中,deparse_vector2(strings)需要0.8秒,并escape_chars(strings)需要0.165秒.
我不知道用R代码做更快的方法,但是我确实决定尝试在C中实现它,包含在一个名为R的函数中deparse_vector3.这很粗糙(而且我远不是专业的C程序员),但它似乎适用于您的示例:https://gist.github.com/wch/e3ec5b20eb712f1b22b2
在我的系统(Mac,R 3.1.1)上,deparse_vector2速度比测试速度快deparse_vector5倍,这比测试中的5倍差.
我的deparse_vector3功能只比快3倍deparse_vector2.可能还有改进的余地.
> system.time(out1 <- deparse_vector1(strings))
user system elapsed
8.459 0.009 8.470
> system.time(out2 <- deparse_vector2(strings))
user system elapsed
0.368 0.007 0.374
> system.time(out3 <- deparse_vector3(strings))
user system elapsed
0.120 0.001 0.120
Run Code Online (Sandbox Code Playgroud)
但我认为这不会正确处理非ASCII字符编码.以下是R源代码处理方式的示例:https://github.com/wch/r-source/blob/trunk/src/main/grep.c#L704-L739
编辑:这似乎处理UTF-8确定,虽然我可能在测试中遗漏了一些东西.