こんにちは、つくたろうです。
今日はPythonについての記事を書いていきたいと思います。
その中でも特に、日本語ドメインなどを扱う中で登場する「Punycode」について扱っていきたいと思います!
はじめに(Punycodeについて)
今回は先述の通り、「Punycode(ピュニコード、プニコード)」を扱う記事を書いていきます。
ピュニコードとは、マルチバイト文字(Unicode)を含んだドメイン名をDNSで使えるような文字列に変換する仕組みです。
ユニコードを含んだドメインとは、ざっくり言ってしまえば「数字とアルファベット以外のドメイン」のことですね。例えば「旅行.jp」のような日本語ドメインなんかがこれにあたります。
このようなUnicodeの含まれたドメインは、そのままではDNSで裁くことができません。DNSで対応できるドメインは、「アルファベット」「数字」「ハイフン」によって構成されたものだけであると定義されているためです。したがって、UnicodeのドメインもDNSによってアクセスできるように決められた変換の手続きがPunycodeというわけです。
具体的には、Unicodeの文字列を「xn--」で始まるASCII文字列へと変換します。「旅行.jp」なら「xn--zfvo28e.jp」へと変換されます。このような変換によって、DNSで「旅行.jp」を名前解決することが可能となります。
また最近では、セカンドレベルドメインだけでなく、トップレベルドメインについても2バイト文字が現れるドメインが増えてきています。「僕だけの.世界」とか、「どこいっちゃったの.みんな」とかですね。(これらはドメインハックによく使われます。ドメインハックについては以前詳しく記事を書いたので、そちらを参照してください。)
こういったドメインに関しても、Punycodeによる変換がレベル単位で行われたうえで名前解決が行われます。(例:「僕だけの.世界」→「xn--08j3a5b142t.xn--rhqv96g」、「どこいっちゃったの.みんな」→「xn--n8j3azbhjb1b8b6l.xn--q9jyb4c」)
上記のような変換の取り決めによって、日本語などを含んだユニークなドメインを扱うことができているというわけですね。
ということで、前置きはこの程度にしておきたいと思います。より詳細なDNSの仕様・仕組みなどについて知りたい方は、以下の書籍などを参考にしていただければと思います。
PythonによるPunycode変換
さて、ここから本題です。この「Unicodeを含んだドメイン名の変換」、つまりPunycode変換をPythonで実装したい。
ドメインの管理スクリプトやURL短縮サービスなど「ドメイン名の入出力」があるアプリを書くときには、やっぱりマルチバイトな文字列がどうしてもエラーの原因になってしまいがちです。
これらのエラーを避けるためには、いかなるドメインについてもシングルバイト文字として扱いたい。要するに、文字列の入り口と出口の部分にPunycodeの変換を通すような仕組みが欲しい。
これは自前で実装する必要はありません。Pythonにはピュニコードの変換を行うための「punycode」というライブラリが用意されています。Pythonって大抵のことはそれをやってくれるライブラリが見つかるので助かりますね。
ということで、今回はこの「punycode」ライブラリを使ってPunycode変換の実装をしていきます。(実装と言っても、用意されている関数を使うだけです。)
PythonのPunycode変換ライブラリ「punycode」を使う
「punycode」のインストール
「punycode」はPyPIのパッケージとして登録されているので、いつも通りpip
コマンドでのインストールが可能です。
pip install punycode
「punycode」ライブラリによるPunycodeの変換
Pythonの「punycode」ライブラリでは、Punycodeの変換に「convert()
」という関数を使います。
このpunycode.convert()
一つでUnicode⇔Punycodeの相互変換が可能です。
このライブラリ・関数を使って実際に簡単な変換コードを書いてみました:
import punycode # punycodeパッケージをimport # 変換用のUnicodeドメイン unicode1 = "旅行.jp" unicode2 = "僕だけの.世界" unicode3 = "どこいっちゃったの.みんな" # Punycodeに変換 punycode1 = punycode.convert(unicode1) punycode2 = punycode.convert(unicode2) punycode3 = punycode.convert(unicode3) # Punycode変換結果を出力 print(f"{unicode1} => {punycode1}") print(f"{unicode2} => {punycode2}") print(f"{unicode3} => {punycode3}") # 旅行.jp => xn--zfvo28e.jp # 僕だけの.世界 => xn--08j3a5b142t.xn--rhqv96g # どこいっちゃったの.みんな => xn--n8j3azbhjb1b8b6l.xn--q9jyb4c # さらに変換(Unicodeに戻す) unicode1_reconv = punycode.convert(punycode1) unicode2_reconv = punycode.convert(punycode2) unicode3_reconv = punycode.convert(punycode3) # Punycode変換結果を出力 print(f"{punycode1} => {unicode1_reconv}") print(f"{punycode2} => {unicode2_reconv}") print(f"{punycode3} => {unicode3_reconv}") # xn--zfvo28e.jp => 旅行.jp # xn--08j3a5b142t.xn--rhqv96g => 僕だけの.世界 # xn--n8j3azbhjb1b8b6l.xn--q9jyb4c => どこいっちゃったの.みんな
出力結果を見ると、一つのpunycode.convert()
関数を使って相互に変換できていることがわかると思います。
シングルバイトのドメインはそのまま返ってくる
元々シングルバイトのドメイン名(tsukutarou.netなど)はpunycode.convert()
関数に通してもそのままの形で返ってきます。Unicodeを含んでいる文字列だけがピュニコードに変換されるようになっています。
具体的なコードは次の通りです:
import punycode # punycodeパッケージをimport # シングルバイトのドメイン名をPunycode変換 ASCII_domain = "tsukutarou.net" result = punycode.convert(ASCII_domain) print(result) # tsukutarou.net
このため、入力する際にUnicodeを含んだドメインであるかの分岐処理などを入れる必要はなさそうですね。
オススメ書籍等
Pythonを書いていくにあたって以下の書籍はとても使いやすく、独自の視点で書かれている項目も多く他の書籍には載っていない点も網羅的に学べるため非常に重宝しています。皆さんにもオススメしておきます。
また、Python初心者の方には以下の書籍がオススメです(イラストや漫画が豊富で理解しやすくなっています)。
おわりに
ということで今回は、Pythonでピュニコードの変換を行うためのライブラリ「punycode」の紹介でした。
ドメインを扱うドメインマニアとしてはぜひ紹介しておきたいライブラリでしたので、今回こうして記事にできてよかったです。(idnaライブラリなんかを使った変換の記事は見かけるのですが、このライブラリを使っている記事はなかったと思います。)
こうした便利なライブラリを使って、皆さんもどんどんプログラミングしていきましょう!
ということで、今回の記事はこの辺にしたいと思います。ここまで読んでいただき、ありがとうございました!
2023/03/14 つくたろう
P.S. 今回紹介したマルチバイトドメインはまだ空きがあります。興味があれば取得してみてください。
カテゴリ: