Moo*_*per 14 r character-encoding
我注意到,我可以使用一些希腊字母作为名称,而另一些则是非法的,或者只是拉丁字母的别名。
基本上,我可以使用?或µ(尽管在打印时?会更改为并用作同盟者)ßß?
list(? = 1)
# $ß
# [1] 1
list(? = 1)
# $µ
# [1] 1
Run Code Online (Sandbox Code Playgroud)
?,?,?,?,?,?,?,?,?,?,?和?允许,但充当拉丁字母的联盟。
list(? = 1)
# $a
# [1] 1
?a <- 42
aa
# [1] 42
GG <- 33
??
# [1] 33
Run Code Online (Sandbox Code Playgroud)
我测试过的其他字母只是“不起作用”:
? <- 1
# Error: unexpected input in "\"
? <- 1
# Error: unexpected input in "\"
? <- 1
#Error: unexpected input in "\"
Run Code Online (Sandbox Code Playgroud)
我很惊讶,?因为它是由package定义wrapr的define_lambda,因此我认为这取决于系统。
我知道外观相似或相同的字符可能具有不同的编码,并且其中某些字符在应用程序之间进行复制/粘贴时效果不佳,此问题的代码在粘贴回RStudio时返回描述的输出。
?make.names 说:
语法上有效的名称由字母,数字和点或下划线字符组成,并以字母或点开头,后跟数字
因此,部分问题是:什么是字母?这是怎么回事?
进一步来说:
µ和?(或ß)可以安全使用。?(intToUtf8(955))在似乎经常被wrapr用户使用,而在我的系统上不可用。ø看起来很酷,并且似乎可以在我的系统上运行)我正在寻找一个(或2个)字符函数名称,该名称与现有或常用名称不会冲突,并且看起来有点时髦,这提示了所有这些。.已经使用了很多,我也已经使用了..。
来自sessionInfo():
R version 3.5.2 (2018-12-20)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)
Matrix products: default
locale:
[1] LC_COLLATE=English_United Kingdom.1252 LC_CTYPE=English_United Kingdom.1252 LC_MONETARY=English_United Kingdom.1252
[4] LC_NUMERIC=C LC_TIME=English_United Kingdom.1252
Run Code Online (Sandbox Code Playgroud)
小智 12
我绝对不是专家,但让我们尝试分析问题。最后,编译器需要理解您的R代码,因此make.names()的源代码可能会有所帮助:
names <- as.character(names)
names2 <- .Internal(make.names(names, allow_))
if (unique) {
o <- order(names != names2)
names2[o] <- make.unique(names2[o])
}
names2
Run Code Online (Sandbox Code Playgroud)
现在,.Internal()调用R解释器(用C编写),因此我们需要更深入一些。可以在以下位置找到负责处理make.names()请求的C代码:https : //github.com/wch/r-source/blob/0dccb93e114b00b2fcbe75e8721f11a8f2ffdff4/src/main/character.c
一小段:
SEXP attribute_hidden do_makenames(SEXP call, SEXP op, SEXP args, SEXP env)
{
SEXP arg, ans;
R_xlen_t i, n;
int l, allow_;
char *p, *tmp = NULL, *cbuf;
const char *This;
Rboolean need_prefix;
const void *vmax;
checkArity(op ,args);
arg = CAR(args);
if (!isString(arg))
error(_("non-character names"));
n = XLENGTH(arg);
allow_ = asLogical(CADR(args));
if (allow_ == NA_LOGICAL)
error(_("invalid '%s' value"), "allow_");
PROTECT(ans = allocVector(STRSXP, n));
vmax = vmaxget();
for (i = 0 ; i < n ; i++) {
This = translateChar(STRING_ELT(arg, i));
l = (int) strlen(This);
/* need to prefix names not beginning with alpha or ., as
well as . followed by a number */
need_prefix = FALSE;
if (mbcslocale && This[0]) {
int nc = l, used;
wchar_t wc;
mbstate_t mb_st;
const char *pp = This;
mbs_init(&mb_st);
used = (int) Mbrtowc(&wc, pp, MB_CUR_MAX, &mb_st);
pp += used; nc -= used;
if (wc == L'.') {
if (nc > 0) {
Mbrtowc(&wc, pp, MB_CUR_MAX, &mb_st);
if (iswdigit(wc)) need_prefix = TRUE;
}
} else if (!iswalpha(wc)) need_prefix = TRUE;
} else {
if (This[0] == '.') {
if (l >= 1 && isdigit(0xff & (int) This[1])) need_prefix = TRUE;
} else if (!isalpha(0xff & (int) This[0])) need_prefix = TRUE;
}
if (need_prefix) {
tmp = Calloc(l+2, char);
strcpy(tmp, "X");
strcat(tmp, translateChar(STRING_ELT(arg, i)));
} else {
tmp = Calloc(l+1, char);
strcpy(tmp, translateChar(STRING_ELT(arg, i)));
}
if (mbcslocale) {
/* This cannot lengthen the string, so safe to overwrite it. */
int nc = (int) mbstowcs(NULL, tmp, 0);
if (nc >= 0) {
wchar_t *wstr = Calloc(nc+1, wchar_t);
mbstowcs(wstr, tmp, nc+1);
for (wchar_t * wc = wstr; *wc; wc++) {
if (*wc == L'.' || (allow_ && *wc == L'_'))
/* leave alone */;
else if (!iswalnum((int)*wc)) *wc = L'.';
}
wcstombs(tmp, wstr, strlen(tmp)+1);
Free(wstr);
} else error(_("invalid multibyte string %d"), i+1);
} else {
for (p = tmp; *p; p++) {
if (*p == '.' || (allow_ && *p == '_')) /* leave alone */;
else if (!isalnum(0xff & (int)*p)) *p = '.';
/* else leave alone */
}
}
// l = (int) strlen(tmp); /* needed? */
SET_STRING_ELT(ans, i, mkChar(tmp));
/* do we have a reserved word? If so the name is invalid */
if (!isValidName(tmp)) {
/* FIXME: could use R_Realloc instead */
cbuf = CallocCharBuf(strlen(tmp) + 1);
strcpy(cbuf, tmp);
strcat(cbuf, ".");
SET_STRING_ELT(ans, i, mkChar(cbuf));
Free(cbuf);
}
Free(tmp);
vmaxset(vmax);
}
UNPROTECT(1);
return ans;
}
Run Code Online (Sandbox Code Playgroud)
如我们所见,使用了诸如wchar_t(http://icu-project.org/docs/papers/unicode_wchar_t.html)之类的依赖于编译器的数据类型。这意味着make.names()的行为取决于用于编译R解释器本身的C编译器。问题是C编译器不是很标准化,因此无法假设字符的行为。包括操作系统,硬件,语言环境等在内的所有内容都可以更改此行为。
总之,如果要保存,我会坚持使用ASCII字符,尤其是在不同操作系统之间共享代码时。