sfでShapefileの読み書きをするときは常にENCODING=を指定したほうがよさげ

r-wakalangで質問があって軽く調べたのでメモ。

Shapefile読み込みの時にoptions = "ENCODING=..."文字コードを指定するというのは徐々に知られてきています。

…というか私も以下の記事で最近知りました。勉強になります。

しかし、どうやら文字コードを指定するのは読み込み時だけでなくて書き込み時も必要みたいです。

sfの文字コードまわりのつらさ

そもそもsfの文字コードまわりはつらみに溢れています。

ご存知のように、Rのデフォルト文字コードがOSや環境によって違うこともさることながら、sf(というかGDAL)は、shapefileだけではなくPostGISやGeoJSON、WKTなどなど様々なデータ形式を想定しているので、文字コードをひとつに決めることができません。それぞれのデータ形式によって求める文字コードが違うからです。

このへんのつらさを垣間見るには以下のissueの議論なんかを眺めてみるといいかもしれません。

そんなわけで、文字コードまわりをsfがいい感じに吸収してくれるという魔法はありません。自分で指定するしかないのです。

GDALのshapefileドライバの仕様

ドライバの仕様は以下のように書かれています。

An attempt is made to read the code page setting in the .cpg file, or as a fallback in the LDID/codepage setting from the .dbf file, and use it to translate string fields to UTF-8 on read, and back when writing. LDID “87 / 0x57” is treated as ISO8859_1 which may not be appropriate.
(http://www.gdal.org/drv_shapefile.html)

つまり、読み込むときも書き込むときもUTF-8でやるよ、と。よさそうです。

でもそのあとの「ISO8859_1が云々」というくだりは何なんでしょう? UTF-8になってるならそんなの気にしなくてよくない…?

と思って読み進めていくと、こんな記述があります。

Layer Creation Options

  • SHPT=type: …
  • ENCODING=value: set the encoding value in the DBF file. The default value is “LDID/87”. It is not clear what other values may be appropriate.

問題はここです。

The default value is “LDID/87”.

上に書かれていたことを思い出してみましょう。

LDID “87 / 0x57” is treated as ISO8859_1 which may not be appropriate.

つまり、書き出しに関しては、文字コードを明示的に指定しないと、UTF-8からISO8859_1への余計な変換が発生してしまうのです。なんと…

(正直なぜこんな仕様になってるのか理由がわかりませんでした…。後方互換性とか? ご存知の方はTwitterとかでそっと耳打ちしていただけるとありがたいです)

shapefile書き込み時の文字コードの指定の仕方

そんな不要な変換を防ぐために、文字コードは明示的に指定しましょう。書き込み時の文字コードは、layer_optionsに指定します。つまり、次のようになります。

# write_sf() は st_write() のラッパー
write_sf(sf_obj, "/path/to/shapefile.shp", layer_options = "ENCODING=UTF-8")

さらに、Windowsの場合は、これだけではなく書き込む前にデータの文字コードUTF-8にしておく必要があります。ちょっとこのあたりややこしいことに気付いたのでもう少し調べます。。

(追記:GitHub版では修正されていました。詳しくはsfでShapefileの読み書きをするときの文字コードの指定方法 - Technically, technophobic.で)

まとめ

組み合わせがちょっといろいろややこしいので、とりあえず今回は書き込み時も注意してくださいというショートノーティスということで。また次回。