删除R / C中的字节顺序标记

时间:2014-11-04 22:46:53

标签: c json r utf-8

This SO post有一个生成带有byte order mark的json的服务器示例。 RFC7159说:

  

实现绝不能在JSON文本的开头添加字节顺序标记。为了互操作性,解析JSON文本的实现可以忽略字节顺序标记的存在,而不是将其视为错误。

目前yajl因此jsonlite阻塞了BOM。我想遵循RFC建议并忽略UTF8字符串中的BOM(如果存在)。有效的方法是什么?一个天真的实现:

if(substr(json, 1, 1) == "\uFEFF"){
  json <- substring(json, 2)
}

但是substr对于大字符串来说有点慢,我不确定这是否是正确的方法。如果存在,是否有更有效的方法在R或C中删除BOM?

2 个答案:

答案 0 :(得分:5)

一个简单的解决方案:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
std::string stripBom(std::string x) {
   if (x.size() < 3)
      return x;

   if (x[0] == '\xEF' && x[1] == '\xBB' && x[2] == '\xBF')
      return x.substr(3);

   return x;
}

/*** R
x <- "\uFEFFabcdef"
print(x)
print(stripBom(x))
identical(x, stripBom(x))
utf8ToInt(x)
utf8ToInt(stripBom(x))
*/

给出

> x <- "\uFEFFabcdef"

> print(x)
[1] "abcdef"

> print(stripBom(x))
[1] "abcdef"

> identical(x, stripBom(x))
[1] FALSE

> utf8ToInt(x)
[1] 65279    97    98    99   100   101   102

> utf8ToInt(stripBom(x))
[1]  97  98  99 100 101 102

编辑:看看R在内部是如何做的可能也是有用的 - 在很多情况下R剥离BOM(例如用于扫描仪和文件阅读器)。参见:

https://github.com/wch/r-source/blob/trunk/src/main/scan.c#L455-L458

https://github.com/wch/r-source/blob/trunk/src/main/connections.c#L3621-L3624

答案 1 :(得分:4)

基于Kevin的Rcpp示例,我使用以下C函数来检查bom:

SEXP R_parse(SEXP x) {
  /* get data from R */
  const char* json = translateCharUTF8(asChar(x));

  /* ignore BOM as suggested by RFC */
  if(json[0] == '\xEF' && json[1] == '\xBB' && json[2] == '\xBF'){
    warning("JSON string contains UTF8 byte-order-mark!");
    json = json + 3;
  }

  /* parse json */
  char errbuf[1024];
  yajl_val node = yajl_tree_parse(json, errbuf, sizeof(errbuf));
}