頑張らないために頑張る

ゆるく頑張ります

Unicodeには「あるのに見えない文字」が存在する

Posted at — Mar 16, 2023

もともとの経緯

ある日、Linuxで実行するためのとあるコマンドをとあるwebページからコピペし実行しようとしましたが、「そんなフォルダもファイルもねぇよ」と怒られてしまいました。存在するのに

細かい内容は割愛しますが、実行したのはcd /hoge/fuga/...(結構長いアドレス).../みたいなコマンドです。このアドレスのフォルダは、特定のアプリケーションをインストールしていると自動的に作成されるため、アプリケーションが導入されているのにこのフォルダが存在しない、ということはあり得ません。

この移動先のアドレスがそこそこ長く、手で入力するのも面倒なので入力間違いがあると困るので、webにあるものをコピペして実行したわけです。コピペしているので、もともとの状態から一言一句変更しておらず、先述のとおりフォルダは存在しているのでエラーが出るようなコマンドでもないはずです。

しかし、なぜかエラーになってしまいました。

ただ、ここでふと気付きました。コピペしたコマンドは動かない。けれど、自分で同じ内容を手で入力すると動く。もちろん、見た目はまったく一緒なのに。怪奇現象かなにかかいな。

・・・ちょっと待って。見えない何かがいるんじゃない?

ZWSPって何者よ

結論から言うと、います。見えなくても「ヤツ」はそこに。その「ヤツ」は「ゼロ幅スペース」という文字です。ええ、文字です、文字じゃないけど。

UnicodeにはZWSP(ゼロ幅スペース)という文字コードが存在しており、webページの組版に用いられることがあります。これはゼロ幅なので一見しただけでは存在しないように見えますが、文字コードとしては確かに存在するデータです。

Wikipediaのゼロ幅スペースによると・・・。

通常、英語などのわかち書きをする言語において、文の途中で改行を入れる場合はスペースの位置で行われる。しかし、スラッシュなどの記号の後などスペースは入らないが改行をしても良い箇所や、日本語などのわかち書きをしない言語において、改行できる位置を明示するためにゼロ幅スペースが用いられる。

とのこと。

たとえば・・・

WordPress「めっちゃ長い文字列・・・改行したい・・・でもスペースで区切られてないからどこで改行すべきかイマイチわからん。せや、スラッシュあるからその直後で改行すりゃ見た目にそんな大きな影響ないやろ」

・・・と、スラッシュの後にZWSPを代入してこれを基準に改行することで、見た目に影響を及ぼさないまま改行する位置を明確に指定することが可能です。

大抵の場合、改行位置という見た目だけの問題なので、それ以外の影響を及ぼすようなことはないでしょう。大抵の場合は

例外は、たとえば「めちゃ長いアドレスを含むコマンドをコピペしたとき」などです。

上記の例で行くと、「めちゃ長いからスラッシュの後にZWSP入れて、それ基準で改行しよ」と処理されるため、見た目には何もないのに実際にはZWSPが存在するせいで、「見た目と実際のデータの内容に差がある」ことになってしまいます。webからコピペしたコマンドが見た目正しいのにエラーを吐くなんていうケースは、このZWSPが悪さをしているかもしれません。許さん。

ZWSPの影響例

一例をば。

cdを使ってフォルダ移動するのですが、移動先フォルダのアドレスが長いため、webページからコピペするとしましょう。ここではcd /usr/hoge/...なんかもうめちゃくちゃ長いアドレス.../testとしています。なお、ここでは移動先フォルダは存在するものとします

$ cd /usr/hoge/...なんかもうめちゃくちゃ長いアドレス.../test
-bash: cd: /usr/hoge/...なんかもうめちゃくちゃ長いアドレス.../test: No such file or directory ← 存在するのに?

このように、移動先フォルダは存在するという前提にもかかわらず、「そんなフォルダないけど」とエラーが返ってきてしまいました。

webからコピペしたコマンドには、たまたま移動先フォルダ部分にZWSPが含まれていたため、本来意図したフォルダ名とは異なった「ZWSPを含むフォルダ」に向かってcdしようとしてしまい、「そんなフォルダないぞ」を怒られたわけです。やっぱり許さん。

対処法

エラーの原因がZWSPであると思われる場合は、文字コードを指定して除外するのが最速です。ただし、ZWSPの文字コードにもいくつかパターンがあり、どれに該当しているかを調査するのは少し手間かもしれません。また、そもそも文字コードベースでの指定ができないエディタでは、この方法が利用できません。

「それなら同じ内容を手で入力すればいいじゃん」は、まぁ、単純かつ有効な方法ではあります。ただ、今回はそもそも手入力したくないような長い文字列をコピペしようとしているのに、手入力するってのは本末転倒になってしまうのが悩ましいところ。

なお、意図せずZWSPを含ませないようにするには、Markdownならコマンドやプログラムコードをバッククォートで囲うべきでしょう。HTMLであれば<code>タグを利用すれば良いかと。よくコマンドやコードをバッククォートで囲うのは、CMSやSSGがHTMLを生成する際にコードであることを主張するようなレイアウトでページを生成するほか、余計なコードを埋め込まないよう制御できる利点があるわけなんですね。

まとめ

余計な文字を入れんな。いや、ホント。

見えないとかどんなトラップよ?ただ、こういう制御を行う文字があるっていうのを知っているなら対処は可能です。実際にトラブルになっても、知っているのと知らないのとでは天と地ほどの差があるでしょう。

参考

  1. ゼロ幅スペース
  2. Unicode ゼロ幅スペースを利用して情報を隠して仕込む
  3. ゼロ幅スペースの謎を解く
  4. 本当に大切なものは目に見えない ~Unicodeの目に見えない改行文字に苦しめられた話~
comments powered by Disqus