UTF-8文字列を含むURL

内閣官房 国民保護ポータルサイト 避難施設の一覧表 にあるPDFで、例えば 三重県 を選ぶと、三重県の避難施設一覧の表が現れる。各避難施設にはGoogleマップとYahooマップへのリンクが付いている。この種のリンクは緯度・経度を指定するのが一般的だが、ここでは住所の文字列を指定している。例えば最初の津市立豊が丘小学校のGoogleマップへのリンクは「三重県津市高野尾町3214番地1」という住所を指定している。しかも、その住所がURLエンコード(% で始まる16進表記)されておらず、生UTF-8バイト列になっている。

次の三つのリンクでテストしてみよう。

最初のリンクは生UTF-8のバイト列で指定している。これはUTF-8なWebページからのリンクであれば正しく動作する。

これをURLエンコードすると第2のURLになる。

ところが、このPDFファイルをMacのSafariまたは「プレビュー」アプリで開くと、第3のURLのように解釈されて、検索文字列は ä で始まる文字化けしたような文字列になる。

import urllib.parse

s = "%C3%A4%C2%B8%C2%89%C3%A9%C2%87%C2%8D%C3%A7%C2%9C%C2%8C%C3%A6%C2%B4%C2%A5%C3%A5%C2%B8%C2%82%C3%A9%C2%AB%C2%98%C3%A9%C2%87%C2%8E%C3%A5%C2%B0%C2%BE%C3%A7%C2%94%C2%BA%C3%AF%C2%BC%C2%93%C3%AF%C2%BC%C2%92%C3%AF%C2%BC%C2%91%C3%AF%C2%BC%C2%94%C3%A7%C2%95%C2%AA%C3%A5%C2%9C%C2%B0%C3%AF%C2%BC%C2%91"

urllib.parse.unquote(s)
'ä¸\x89é\x87\x8dç\x9c\x8cæ´¥å¸\x82é«\x98é\x87\x8eå°¾ç\x94ºï¼\x93ï¼\x92ï¼\x91ï¼\x94ç\x95ªå\x9c°ï¼\x91'

そこで、ChatGPT 4oやClaude 3.5 Sonnetに

URLエンコードされた文字列 "%C3%A4%C2%B8%C2%89%C3%A9%C2%87%C2%8D%C3%A7%C2%9C%C2%8C%C3%A6%C2%B4%C2%A5%C3%A5%C2%B8%C2%82%C3%A9%C2%AB%C2%98%C3%A9%C2%87%C2%8E%C3%A5%C2%B0%C2%BE%C3%A7%C2%94%C2%BA%C3%AF%C2%BC%C2%93%C3%AF%C2%BC%C2%92%C3%AF%C2%BC%C2%91%C3%AF%C2%BC%C2%94%C3%A7%C2%95%C2%AA%C3%A5%C2%9C%C2%B0%C3%AF%C2%BC%C2%91" を解読してください。

と聞いてみると、正しく「三重県津市高野尾町3214番地1」と答える。どうやって解読したのか、Pythonで書いてくれといっても、うまく書けない。

しかし、いろいろ聞き方を変えてみると、ChatGPT 4oが正しい答えをくれた。

import urllib.parse

s = "%C3%A4%C2%B8%C2%89%C3%A9%C2%87%C2%8D%C3%A7%C2%9C%C2%8C%C3%A6%C2%B4%C2%A5%C3%A5%C2%B8%C2%82%C3%A9%C2%AB%C2%98%C3%A9%C2%87%C2%8E%C3%A5%C2%B0%C2%BE%C3%A7%C2%94%C2%BA%C3%AF%C2%BC%C2%93%C3%AF%C2%BC%C2%92%C3%AF%C2%BC%C2%91%C3%AF%C2%BC%C2%94%C3%A7%C2%95%C2%AA%C3%A5%C2%9C%C2%B0%C3%AF%C2%BC%C2%91"

urllib.parse.unquote(s).encode('latin1').decode('utf-8')
'三重県津市高野尾町3214番地1'

つまり、Safariやプレビューは、生UTF-8の文字列をLatin-1だと解釈したようだ:

import urllib.parse

urllib.parse.quote('三重県津市高野尾町3214番地1'.encode("utf-8").decode("latin1"))
'%C3%A4%C2%B8%C2%89%C3%A9%C2%87%C2%8D%C3%A7%C2%9C%C2%8C%C3%A6%C2%B4%C2%A5%C3%A5%C2%B8%C2%82%C3%A9%C2%AB%C2%98%C3%A9%C2%87%C2%8E%C3%A5%C2%B0%C2%BE%C3%A7%C2%94%C2%BA%C3%AF%C2%BC%C2%93%C3%AF%C2%BC%C2%92%C3%AF%C2%BC%C2%91%C3%AF%C2%BC%C2%94%C3%A7%C2%95%C2%AA%C3%A5%C2%9C%C2%B0%C3%AF%C2%BC%C2%91'

実際にこのようなPDFファイルを作ってみよう。次のファイルをUTF-8で作り、test.tex という名前で保存する。

\documentclass{jlreq}
\usepackage{hyperref}
\begin{document}

\href{https://www.google.com/maps?q=三重県津市高野尾町3214番地1}{リンク1}

\href{https://www.google.com/maps?q=%E4%B8%89%E9%87%8D%E7%9C%8C%E6%B4%A5%E5%B8%82%E9%AB%98%E9%87%8E%E5%B0%BE%E7%94%BA%EF%BC%93%EF%BC%92%EF%BC%91%EF%BC%94%E7%95%AA%E5%9C%B0%EF%BC%91}{リンク2}

\href{https://www.google.com/maps?q=%C3%A4%C2%B8%C2%89%C3%A9%C2%87%C2%8D%C3%A7%C2%9C%C2%8C%C3%A6%C2%B4%C2%A5%C3%A5%C2%B8%C2%82%C3%A9%C2%AB%C2%98%C3%A9%C2%87%C2%8E%C3%A5%C2%B0%C2%BE%C3%A7%C2%94%C2%BA%C3%AF%C2%BC%C2%93%C3%AF%C2%BC%C2%92%C3%AF%C2%BC%C2%91%C3%AF%C2%BC%C2%94%C3%A7%C2%95%C2%AA%C3%A5%C2%9C%C2%B0%C3%AF%C2%BC%C2%91}{リンク3}

\end{document}

次に、LaTeXがインストールされた環境で lualatex test と打ち込むと、test.pdf というPDFファイルができる。これをいろいろなブラウザやPDFビューアで開いてリンクをクリックしてみると、最初に挙げた3通りのリンクの動作が確認できる。