【R】 日本語を含むコードを丸ごとエスケープさせる方法

# 趣旨
パッケージを作成したり他人とコードを共有する場合、コードの日本語をエスケープさせるほうが良いことが多いです。そこで、自作関数などに含まれる日本語を簡単にエスケープさせる方法を編み出したのでTipsとして記しておきます。

# 使うパッケージ

- stringi (必須）
- stringr (必須)
- clipr (推奨)

```R
library(stringi); library(stringr); library(clipr)
```

# 流れ

① 関数を読み込む ⇒ ② 変換後の内容をクリップボードに保存 ⇒ ③ スクリプトやメモ帳に貼り付け

# 今回変換したい関数

適当な法隆寺関数を用意しました。
この関数に含まれる日本語を手作業ではなくRを使って何とかエスケープさせましょう。


```R:今回のターゲット
f1 <- function(){
  print("正岡子規") # 小峠ではない
  fx <- function(){cat("有名な\nやーつ\n")}
  fx()
  "a" %>% 
    print() 
  print(paste("柿食へば", 
              "鐘が鳴るなり", 
              "法隆寺"))
  # いい俳句だ
}
```
```R:関数の実行結果
> f1()
[1] "正岡子規"
有名な
やーつ
[1] "a"
[1] "柿食へば 鐘が鳴るなり 法隆寺"
```


# やってみよう

コードを実行すると、クリップボードに置換後の関数が自動で記録されます。

**2020/03/09 追記: 大幅変更**

## コメントアウトは置換しない場合

```R
f1 %>% 
  getSrcref %>%
  as.character %>%
  stringi::stri_escape_unicode() -> tx
while(sum(str_detect(tx, pattern = "#.*\\\\u")) > 0) {
  tx <- stringi::stri_replace_all_regex(tx, pattern = "#(.*)\\\\u", replacement = "#$1\\\\_u")} %>%
  stringr::str_replace_all(pattern = "^.*\\\\u", replacement = "\\\\\\\\u") %>%
  stringr::str_replace_all(., "\\\\_u", "\\\\u") %>%
  stringi::stri_unescape_unicode() %>% 
  clipr::write_clip()
```
```R:置換後のクリップボードの内容
function(){
  print("\u6b63\u5ca1\u5b50\u898f") # 小峠ではない
  fx <- function(){cat("\u6709\u540d\u306a\n\u3084\u30fc\u3064\n")}
  fx()
  "a" %>% 
    print() 
  print(paste("\u67ff\u98df\u3078\u3070", 
              "\u9418\u304c\u9cf4\u308b\u306a\u308a", 
              "\u6cd5\u9686\u5bfa"))
  # いい俳句だ
}
```
```R:置換後の関数の実行結果
> f2 <- function(){
    print("\u6b63\u5ca1\u5b50\u898f") # 小峠ではない
    fx <- function(){cat("\u6709\u540d\u306a\n\u3084\u30fc\u3064\n")}
    fx()
    "a" %>% 
      print() 
    print(paste("\u67ff\u98df\u3078\u3070", 
                "\u9418\u304c\u9cf4\u308b\u306a\u308a", 
                "\u6cd5\u9686\u5bfa"))
    # いい俳句だ
  }

> f2()
[1] "正岡子規"
有名な
やーつ
[1] "a"
[1] "柿食へば 鐘が鳴るなり 法隆寺"
```

## コメントアウトも置換する場合

```R
f1 %>% 
  getSrcref %>%
  as.character %>%
  stringi::stri_escape_unicode() %>%
  stringr::str_replace_all(pattern = "\\\\u", replacement = "\\\\\\\\u") %>%
  stringi::stri_unescape_unicode() %>% 
  clipr::write_clip()
```
```R:置換後のクリップボードの内容
function(){
  print("\u6b63\u5ca1\u5b50\u898f") # \u5c0f\u5ce0\u3067\u306f\u306a\u3044
  fx <- function(){cat("\u6709\u540d\u306a\n\u3084\u30fc\u3064\n")}
  fx()
  "a" %>% 
    print() 
  print(paste("\u67ff\u98df\u3078\u3070", 
              "\u9418\u304c\u9cf4\u308b\u306a\u308a", 
              "\u6cd5\u9686\u5bfa"))
  # \u3044\u3044\u4ff3\u53e5\u3060
}

```
# 注意点

## 遵守すべきこと

- data.frameの各列やリストの各要素にアクセスする際、「`$`」の使用は避けてください。これは、`$日本語の文字列`とするとエスケープした文字列をRが上手く処理できないためです。つまり、日本語の文字列が必ず`""`で囲う形になるようにコードを修正します。以下の例を参考にしてください。

```R
#Example Data
> lst <- list("い" = 1, "ろ" = 2)
> df <- data.frame("は" = 1, "に" = 2)
```
```R
# このような記述は避ける
> lst$い
[1] 1

> df$は
[1] 1

# このように書き換える
> lst[["い"]]
[1] 1

> df[["は"]]
[1] 1
```

## そうでもない問題（解消）

~~実行結果には全く影響はないですが、もし必要であれば一部手直しが必要です。~~

- ~~置換後はコメント`#`は消えてしまいます。~~
- ~~引数内の改行・パイプ演算子毎の改行も消えてしまいます。~~

~~詳しくは上の例を参考にしてください。~~

**2020/03/09 追記: この問題を解決しました。**
[【R】 関数のコードを文字列として取得する - Qiita](https://qiita.com/zakkiiii/items/967583f8d46f1ef79ab2)

# おわりに
いちいち変換してらんないので、めっちゃ楽になりました（自画自賛）
お試しあれ。

Enjoy!

おしまい。