2016-07-07 14 views
6

Ich habe herausgefunden, wie man Unicode-Strings schreibt, aber immer noch verwirrt, warum es funktioniert.Wie schreibe ich eine Unicode-Zeichenkette in eine Textdatei in R Windows?

str <- "ỏ" 
Encoding(str) # UTF-8 
cat(str, file="no-iconv") # Written wrongly as <U+1ECF> 
cat(iconv(str, to="UTF-8"), file="yes-iconv") # Written correctly as ỏ 

Ich verstehe, warum die no-iconv Ansatz nicht funktioniert. Es ist, weil cat (und writeLines als auch) convert the string into the native encoding first and then to the to= encoding. Unter Windows bedeutet das, dass R zuerst in Windows-1252 konvertiert, was nicht verstehen kann, was zu <U+1ECF> führt.

Was ich nicht verstehe ist, warum der yes-iconv Ansatz funktioniert. Wenn ich richtig verstehe, was hier tut, ist einfach eine Zeichenfolge mit der UTF-8 Codierung zurückzugeben. Aber str ist schon in UTF-8! Warum sollte iconv einen Unterschied machen? Wenn iconv(str, to="UTF-8") an cat übergeben wird, sollte nicht auch cat alles noch einmal durch Umwandlung in Windows-1252 durcheinander bringen?

+0

Ich kenne oder benutze R nicht selbst, aber wenn ich nur die Dokumentation lese, gibt 'cat() 'Zeichenketten" so wie sie sind "aus, und der' mark' Parameter von 'iconv()' ist standardmäßig true Aufrufen von 'iconv (str, to =" UTF-8 ")' markiert seine Ausgabe explizit als UTF-8, bevor es an 'cat()' übergeben wird. Vielleicht markiert 'str <-" ỏ "' nicht gleich "str"? Sie können 'enc2utf8 (str)' oder 'Encoding (str) <-" UTF-8 "' verwenden, um 'str' als UTF-8 explizit zu konvertieren und zu markieren, ohne' iconv() 'zu verwenden. Das macht wahrscheinlich einen Unterschied für 'cat()'. –

Antwort

2

Ich denke, die Codierung von (eine Kopie von) str zu "unknown" vor der Verwendung cat() ist weniger Magie und funktioniert genauso gut. Ich denke, das sollte unerwünschte Zeichensatzkonvertierungen in cat() vermeiden. Hier

ist ein erweitertes Beispiel zu zeigen, was ich denke, im ursprünglichen Beispiel passiert:

print_info <- function(x) { 
    print(x) 
    print(Encoding(x)) 
    str(x) 
    print(charToRaw(x)) 
} 

cat("(1) Original string (UTF-8)\n") 
str <- "\xe1\xbb\x8f" 
Encoding(str) <- "UTF-8" 
print_info(str) 
cat(str, file="no-iconv") 

cat("\n(2) Conversion to UTF-8, wrong input encoding (latin1)\n") 
## from = "" is conversion from current locale, forcing "latin1" here 
str2 <- iconv(str, from="latin1", to="UTF-8") 
print_info(str2) 
cat(str2, file="yes-iconv") 

cat("\n(3) Converting (2) explicitly to latin1\n") 
str3 <- iconv(str2, from="UTF-8", to="latin1") 
print_info(str3) 
cat(str3, file="latin") 

cat("\n(4) Setting encoding of (1) to \"unknown\"\n") 
str4 <- str 
Encoding(str4) <- "unknown" 
print_info(str4) 
cat(str4, file="unknown") 

In einem "Latin-1" locale (siehe ?l10n_info), wie von R auf Windows verwendet, Ausgabedateien "yes-iconv", "latin" und "unknown" sollte korrekt sein (Bytefolge 0xe1, 0xbb, 0x8f das ist "ỏ").

In einem Gebietsschema "UTF-8" sollten die Dateien "no-iconv" und "unknown" korrekt sein.

Die Ausgabe des Beispielcodes ist wie folgt, R 3.3.2 64-Bit-Windows-Version mit auf Wine ausgeführt wird:

(1) Original string (UTF-8) 
[1] "ỏ" 
[1] "UTF-8" 
chr "<U+1ECF>""| __truncated__ 
[1] e1 bb 8f 

(2) Conversion to UTF-8, wrong input encoding (latin1) 
[1] "á»\u008f" 
[1] "UTF-8" 
chr "á»\u008f" 
[1] c3 a1 c2 bb c2 8f 

(3) Converting (2) explicitly to latin1 
[1] "á»" 
[1] "latin1" 
chr "á»" 
[1] e1 bb 8f 

(4) Setting encoding of (1) to "unknown" 
[1] "á»" 
[1] "unknown" 
chr "á»" 
[1] e1 bb 8f 

Im ursprünglichen Beispiel iconv() den Standard from = "" Argument verwendet, die Umwandlungsmittel aus das aktuelle Gebietsschema, das effektiv "latin1" ist. Da die Codierung von str eigentlich "UTF-8" ist, wird die Byte-Darstellung der Zeichenfolge in Schritt (2) verzerrt, aber dann implizit durch cat() wiederhergestellt, wenn sie (vermutlich) die Zeichenfolge zurück in das aktuelle Gebietsschema konvertiert, wie in die äquivalente Umwandlung in Schritt (3).