本当に大切なものは目に見えない ~Unicodeの目に見えない改行文字に苦しめられた話~

Fringe81アドベントカレンダーの4日目です。
みなさん、おはこんばんちは。Lil Pacy a.k.a ぺしおです。

前日は大先輩@pastelIncの、
[『この件は誰が決めるんですか？となったときのデリゲーションポーカー』](http://pastelinc.hatenablog.com/entry/2019/12/03/193553)でした。

普段はElmを書いておりますが、
今回の記事では、Unicodeの少し深い浅瀬に潜ってみようと思います。
（頭悪そうな書き出しですみません。）

## TL;DR

Unicodeの文字を扱う際には、「視認できない文字」や「目視では全く同じでも、実際は全く別の文字」が存在していてセキュリティ上のリスクにも繋がるので注意が必要である。


## 今回苦しめられたあいつ

 ←こいつのこと

```
  
```
↑こいつのこと

こいつのこと→` `

やはり、どう頑張っても目に見えない、プレビューに表示されない。
というかQiitaのエディタに貼っつけると消されてしまう。

## 事の発端
### slackのメッセージが勝手に改行される問題

SlackBotの表示がバグってしまっていた
![6e29f956.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170241/00ce00c2-d6f2-72aa-e78a-20c235410f26.png)

ログに表示しても何かが入ってるようには見えない
![722c2f9b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170241/dfd882da-243b-62c0-a7e2-962d3086efce.png)

Block Kit Builderにコピペしてみる
![bc2148c5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170241/4a111f58-1286-331f-7c76-be9795791aa9.png)

やはり、改行されてしまう
![c58fabb9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170241/efb8d9e7-6632-7b57-8ddb-55cf5e0c577c.png)

よくよく右側を見ると...
![3bb1c74a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170241/68033dcb-0c7e-e1f4-c222-835d624d285a.png)

**Gotcha!!（捕まえた！！**)

この赤丸、そのままコピペで検索しても何も出てこなかったため一旦パーセントエンコーディングしてみた。

```js:js
encodeURI(' ');
// => "%E2%80%A8"
```

`"%E2%80%A8"`こいつでググってみると`U+2028`というUnicodeの改行文字だとわかった

今回は、リプレイスして解決。

```js:js
str.replace(/\u2028/g,'')
```

## 他にも色々

![352a95ed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170241/8be73d03-689d-d8ac-93ae-501d287fb839.png)

[出典:一般句読点 General Punctuationの文字一覧 | 0g0.org](https://0g0.org/category/2000-206F/1/)

下の方もおそらく改行

## 捕まえる方法

toUnicode関数を使う

```js:js
function toUnicode(theString) {
  var unicodeString = '';
  for (var i=0; i < theString.length; i++) {
    var theUnicode = theString.charCodeAt(i).toString(16).toUpperCase();
    while (theUnicode.length < 4) {
      theUnicode = '0' + theUnicode;
    }
    theUnicode = '\\u' + theUnicode;
    unicodeString += theUnicode;
  }
  return unicodeString;
}
```

[出典：Convert a String to Unicode in Javascript](http://buildingonmud.blogspot.com/2009/06/convert-string-to-unicode-in-javascript.html)

こいつで

```js:js
toUnicode(' ');
// => "\u2028" Qiitaの記事上では何かが入っているようには見えないけれど。
```

## ちなみにUnicodeを対応するStringにする方法

```js:js
function unicodeToChar(text) {
   return text.replace(/\\u[\dA-F]{4}/gi, 
          function (match) {
               return String.fromCharCode(parseInt(match.replace(/\\u/g, ''), 16));
          });
}
```

[出典：Converting unicode character to string format](https://stackoverflow.com/questions/17267329/converting-unicode-character-to-string-format#answer-22021709)

```js:js
unicodeToChar('\u2028')
// => "" やっぱり目には見えないんだけれどね。
```

## 結論

本当に大切なものは目に見えない（星の王子様風に

## Tips

以下、Unicodeでセキュリティ上考慮しないといけないことに触れた記事。

[Unicode ゼロ幅スペースを利用して情報を隠して仕込む - A painter and a black cat](https://raintrees.net/news/124)
[Unicodeで絶対知っておくべきセキュリティ5つの注意（翻訳）](https://techracho.bpsinc.jp/hachi8833/2017_11_28/48435)
[人間の目で見抜けないURL偽装がフィッシング詐欺に悪用される可能性、Firefoxでの対策はコレ - GIGAZINE](https://gigazine.net/news/20170418-fake-domain-homograph-attack/)

## P.S. 

Macなら以下のコマンドでUnicodeの2028番を生成してクリップボードにコピーできる

```
$ echo -en "\u2028" | pbcopy
```

ぜひいろんなところにはっつけてみていただきたい。

以上。