如果您安装了 Rcpp 和 BH 软件包,这应该是完全可移植的:
library(Rcpp)
library(inline)
csvblanks <- '
string data = as<string>(filename);
ifstream fil(data.c_str());
if (!fil.is_open()) return(R_NilValue);
typedef tokenizer< escaped_list_separator<char> > Tokenizer;
vector<string> fields;
vector<int> retval;
string line;
while (getline(fil, line)) {
int numblanks = 0;
Tokenizer tok(line);
for(Tokenizer::iterator beg=tok.begin(); beg!=tok.end(); ++beg){
numblanks += (beg->length() == 0) ? 1 : 0 ;
};
retval.push_back(numblanks);
}
return(wrap(retval));
'
count_blanks <- rcpp(
signature(filename="character"),
body=csvblanks,
includes=c("#include <iostream>",
"#include <fstream>",
"#include <vector>",
"#include <string>",
"#include <algorithm>",
"#include <iterator>",
"#include <boost/tokenizer.hpp>",
"using namespace Rcpp;",
"using namespace std;",
"using namespace boost;")
)
获取该信息后,您可以调用count_blanks(FULLPATH),它将返回每行空白字段计数的数字向量。
我针对这个文件运行了它:
"DATE","APIKEY","FILENAME","LANGUAGE","JOBID","TRANSCRIPT"
1,2,3,4,5
1,,3,4,5
1,2,3,4,5
1,2,,4,5
1,2,3,4,5
1,2,3,,5
1,2,3,4,5
1,2,3,4,
1,2,3,4,5
1,,3,,5
1,2,3,4,5
,2,,4,
1,2,3,4,5
通过:
count_blanks("/tmp/a.csv")
## [1] 0 0 1 0 1 0 1 0 1 0 2 0 3 0
注意事项
- 很明显,它没有忽略标头,因此它可以使用带有关联 C/C++ 代码的
header 逻辑参数(这将非常简单)。
- 如果您将“空格”(即
[:space:]+)算作“空”,则需要比调用length 更复杂的内容。如果需要,This 是一种潜在的处理方式。
- 它使用定义为here 的Boost 函数
escaped_list_separator 的默认配置。这也可以使用引号和分隔符进行自定义(可以进一步模仿read.csv/read.table。
这将更接近count.fields/C_countfields 的性能,并且无需通过读取每一行来查找您最终想要更优化定位的行来消耗内存。我不认为为返回的数字向量预分配空间会大大提高速度,但您可以查看讨论 here,其中显示了如果需要如何执行此操作。