2014-11-04 48 views
3

This SO post有一個服務器的示例,該服務器用byte order mark生成json。 RFC7159說:刪除R/C中的字節順序標記

實現絕不能在JSON文本的開頭添加一個字節順序標記。爲了互操作性,解析JSON文本的實現可以忽略字節順序標記的存在,而不是將其視爲錯誤。

當前yajl因此jsonlite在物料清單上窒息。我想遵循RFC建議並忽略來自UTF8字符串的BOM(如果存在)。什麼是有效的方法來做到這一點?一個天真的實現:

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

然而substr是大串有點慢,我不知道這是做到這一點的正確方法。如果存在,在R或C中是否有更有效的方法去除BOM?

+1

的BOM的UTF-8表示將EF BB BF。 – borrible 2014-11-04 22:50:37

回答

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

+0

這並不解決OP標記的任何一種語言的問題。 – Vality 2014-11-05 02:13:50

+0

1)Rcpp是R生態系統中非常重要的一部分,對於演示/原型化這些問題非常有用,並且2)將它從C++轉換爲C是微不足道的。請注意,可以使用Rcpp在R_中執行此示例包,雖然'Rcpp :: sourceCpp()'。 – 2014-11-05 02:16:37

+0

也許你會友善地添加C翻譯呢?或者,如果這是可取的,我可以提供一個代碼並進行編輯? – Vality 2014-11-05 02:21:00

4

基於凱文的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)); 
}