URLエンコードは文字を%と16進数2桁に変換する仕組みです
URLにそのまま書けるのは、英数字といくつかの記号だけです。それ以外の文字はいったんバイト列にし、バイトごとに % と16進数2桁で書きます。これがパーセントエンコーディング(URLエンコード)です。日本語はUTF-8で1文字3バイトなので、「日」は %E6%97%A5 の9文字になり、空白は %20 になります(フォーム送信では +)。URLデコードはその逆で、%XX をバイトに戻してから文字として読みます。
同じ文字列でも、URLのどこに入れるかで結果が変わります。検索語のように値ひとつとして入れる文字列は &・=・/・? まで変換する必要があり、すでにURLの形をした文字列は区切り記号を残さないと開けなくなります。このツールは、直した欄を基準にすぐ変換し、URLをパーツごとに分けてデコードし、Shift_JISで作られた古いURLや二重にエンコードされた値も見分けます。URLエンコードは暗号化ではないため、誰でも元の文字列に戻せます。
URLをエンコード・デコードする場面
- 貼り付けたURLが%だらけで読めないとき: チャットや文書に貼ったURLが
%E6%9D%B1%E4%BA%AC…のように見えると、どのページか分かりません。エンコードの欄に貼ると、検索語やパスが日本語で読めます。 - 日本語の検索語や商品名をリンクに入れるとき: 「A&B」や「C++」をそのまま付けると、
&以降が別の項目になり、+が空白として読まれます。値ひとつの規則で変換してから付ければ、そのまま渡せます。 - ログインや決済のあとに戻るURLを値として入れるとき:
redirect_uriやreturnUrlに入れるURLは、内側のURLをまるごとエンコードしないと、外側のURLと混ざります。 - APIの署名を作るとき: OAuth 1.0の署名やAWS署名バージョン4は、RFC 3986の非予約文字だけを残し、空白を
%20と書く必要があります。1文字違うだけで認証に失敗します。 - アクセスログや解析ツールのURLを読むとき: サーバーのログや流入元には、URLがエンコードされたまま残ります。どの検索語で来たかを見るには、デコードが必要です。
- 古い掲示板・CGIのURLを読むとき: 昔のCGI掲示板やフォームのように、ページをShift_JISで作っているサイトは「日本語」を
%93%FA%96%7B%8C%EAと書くため、UTF-8のデコーダーでは文字化けします。
使い方
- デコードする: 右側のURLエンコードの欄に、%を含むURLや値を貼り付けます。貼り付けた形から規則を選び(URLなら「URL全体」、+と空白が見えるなら「フォーム +」)、左側の元の文字列の欄にデコード結果が出ます。
- エンコードする: 左側の元の文字列の欄に文字列を入力し、入れる場所に合った規則を選びます。検索語・ファイル名・リダイレクト先のように値ひとつなら「値ひとつ」、URL全体なら「URL全体」、HTMLフォームと同じ結果が必要なら「フォーム +」、署名用なら「厳密」です。
- URL分解を見る: 欄の文字列がURLやクエリ文字列なら、スキーム・ホスト・パス・クエリの値・フラグメントに分けて、それぞれデコードして表示します。値の中に別のURLがあれば、「このURLをデコード」でそのURLをもう一度展開できます。複数行のときは、カーソルがある行を分解します。
- 文字コード: 既定は自動判別です。UTF-8として読めなければ、EUC-KR・Shift_JIS・Windows-1252のうち合うものとして読み、横に表示します。古いサイトに合わせてエンコードするときは、自分で選びます。
- 記号マップと関数ごとの結果: 記号を押すと、4つの規則での変換結果と理由が表示されます。言語・関数ごとの結果は、元の文字列の欄の文字列をJavaScript・PHP・Pythonの関数で変換したもので、今の規則と違う文字を強調します。行を押すと、その結果をコピーできます。
4つの規則: 何をそのまま残すか
規則ごとに、英数字以外でそのまま残す記号が違います。ほかのツールやコードと結果が違うときは、たいていこの違いが原因です。
| 規則 | そのまま残す記号(英数字以外) | 空白 | すでにある% | 使う場面 · 同じ関数 |
|---|---|---|---|---|
| 値ひとつ | - _ . ! ~ * ' ( ) | %20 | %25にする | クエリの値・パスの一部 · JavaScript encodeURIComponent() |
| URL全体 | 区切り記号 : / ? # [ ] @ ! $ & ' ( ) * + , ; = と - . _ ~(位置によって数個が異なる) | %20 | そのまま残す | アドレスバー・リンク · ブラウザのURL Standard |
| フォーム + | * - . _ | + | %25にする | HTMLフォーム送信 · URLSearchParams、Java URLEncoder |
| 厳密 | - . _ ~ | %20 | %25にする | OAuth 1.0・AWS署名 · PHP rawurlencode() |
厳密の規則で残す4つの記号はRFC 3986が非予約文字と定めたもので、エンコードしてもしなくても同じURLとして扱われます。値ひとつの規則が ! ' ( ) * まで残すのは、JavaScriptが古い規格RFC 2396の非予約文字に従っているためで、URL Standardもこの集合をcomponent集合として別に定めています。
「フォーム +」の規則は URLSearchParams と同じです。ブラウザが実際にHTMLフォームを送信するときは複数行の入力欄の改行を %0D%0A にしますが、このツールと URLSearchParams は %0A のままにします(Chromium 151で確認)。
記号ごとに見る
混同しやすい記号が、規則ごとにどう変わるかをまとめました。URL全体の欄は、http・httpsのURLのクエリ位置を基準にしています。ツール上部の記号マップでは、35個の記号をすべて押して確かめられます。
| 記号 | 値ひとつ | URL全体(クエリ) | フォーム + | 厳密 | encodeURI() |
|---|---|---|---|---|---|
| 空白 | %20 | %20 | + | %20 | %20 |
| & | %26 | & | %26 | %26 | & |
| = | %3D | = | %3D | %3D | = |
| + | %2B | + | %2B | %2B | + |
| / | %2F | / | %2F | %2F | / |
| ? | %3F | ? | %3F | %3F | ? |
| # | %23 | # | %23 | %23 | # |
| % | %25 | % | %25 | %25 | %25 |
| ~ | ~ | ~ | %7E | ~ | ~ |
| * | * | * | * | %2A | * |
| ' | ' | %27 | %27 | %27 | ' |
| ! | ! | ! | %21 | %21 | ! |
| あ | %E3%81%82 | %E3%81%82 | %E3%81%82 | %E3%81%82 | %E3%81%82 |
URL全体の規則が % をそのまま残すのは、すでにエンコードされた %XX を守るためです。その代わり、文字としての%が含まれている場合は、後ろの2文字が16進数かどうかを別に確認する必要があるので、ツールはそうした%の個数を知らせます。PHPの urlencode() はフォームの規則に近いものの、* も %2A に変換します。Pythonの quote() は、厳密の規則に / だけを加えて残します。
%20と+、空白はどう読まれるか
空白を + と書くのは、HTMLフォーム送信(application/x-www-form-urlencoded)の規則です。パスの + は単なるプラス記号で、クエリでも、受け取る側がどの関数でデコードするかによって、空白になることもプラスのまま残ることもあります。本物のプラスを %2B、空白を %20 と書けば、どちらでも同じ意味に読まれます。
| 関数 | 結果 | +を空白にする |
|---|---|---|
JavaScript decodeURIComponent() | a+b c+ | いいえ |
JavaScript URLSearchParams | a b c+ | はい |
PHP urldecode() | a b c+ | はい |
PHP rawurldecode() | a+b c+ | いいえ |
Python unquote() | a+b c+ | いいえ |
Python unquote_plus() | a b c+ | はい |
このツールは、フォーム +の規則でだけ + を空白として読みます。値ひとつや厳密の規則でデコードして + が残ったときは、ステータス行に「フォーム +の規則で読む」ボタンが出ます。URL全体の規則は構造を守るために + をそのまま残し、下のURL分解でクエリの値だけをフォームの規則でデコードして見せます。
URL全体をエンコードするとき: encodeURIとブラウザの違い
URL全体の変換によく使われる encodeURI() は、区切り記号は残しますが % も変換し、ドメインを別扱いにもしません。ブラウザのアドレスバーはURL Standardに従い、パス・クエリ・フラグメントごとに別の集合を使い、すでにある %XX は残し、日本語ドメインはPunycodeに変換します。このツールのURL全体の規則は、ブラウザ側に合わせています。
| 元の文字列 | encodeURI() | URL全体(URL Standard) |
|---|---|---|
https://example.com/a%20b | https://example.com/a%2520b | https://example.com/a%20b |
https://日本語.jp/ | https://%E6%97%A5%E6%9C%AC%E8%AA%9E.jp/ | https://xn--wgv71a119e.jp/ |
https://example.com/?q=[1] | https://example.com/?q=%5B1%5D | https://example.com/?q=[1] |
https://example.com/?q=it's | https://example.com/?q=it's | https://example.com/?q=it%27s |
https://example.com/?next=https://b.com/?x=1&y=2 | https://example.com/?next=https://b.com/?x=1&y=2 | https://example.com/?next=https://b.com/?x=1&y=2 |
最後の行のように、値の中にURLがそのまま入っていると、どちらの方式でも直せません。外側のURLは y=2 を自分の項目として読んでしまうからです。内側のURLを値ひとつの規則で別にエンコードし、next=https%3A%2F%2Fb.com%2F%3Fx%3D1%26y%3D2 のように付ける必要があります。ツールは、URL全体の規則でこうした値を見つけると、ステータス行で知らせます。
二重エンコードと一段ずつのデコード
エンコード済みの文字列をもう一度エンコードすると、% が %25 になります。そのため %20 は %2520 になり、1回デコードすると %20、もう1回デコードして初めて空白になります。フレームワークやHTTPライブラリが値を自動でエンコードしているのに、コードでもう一度変換したときによく起きます。RFC 3986の2.4節も、同じ文字列を二重にエンコードしたり二重にデコードしたりしないよう定めています。
| 回数 | 結果 | 長さ |
|---|---|---|
| 1回 | %E6%97%A5%E6%9C%AC%20%E8%AA%9E | 30文字 |
| 2回 | %25E6%2597%25A5%25E6%259C%25AC%2520%25E8%25AA%259E | 50文字 |
| 3回 | %2525E6%252597%2525A5%2525E6%25259C%2525AC%252520%2525E8%2525AA%25259E | 70文字 |
エンコードの欄の文字列に %25 と16進数2桁が見えると、ツールは二重エンコードと推測して「もう一段デコード」ボタンを表示します。このボタンは %25XX だけを %XX に戻すので、URLのほかの区切り記号には触れません。ただし、元の文字列に「%20」という文字そのものが入っていた場合は、もう一段デコードするとかえって文字列が変わるため、出どころを確認してください。
Shift_JISでエンコードされた古いURL
現在のURLはUTF-8が基本ですが(RFC 3986の2.5節)、古い日本のサイトはページをShift_JIS(実際にはMicrosoftの拡張であるCP932)で作り、フォームで送った検索語もそのバイト列でエンコードしていました。漢字は1文字2バイトなので、「日」は %93%FA です。URL Standardも、http・httpsのURLのクエリはページの文字コードで、パスは常にUTF-8で変換すると定めています。
| 文字 | UTF-8 | Shift_JIS |
|---|---|---|
| 日 | %E6%97%A5 | %93%FA |
| 本 | %E6%9C%AC | %96%7B |
| あ | %E3%81%82 | %82%A0 |
| ソ | %E3%82%BD | %83%5C |
| A | A | A |
Shift_JISには、2バイト目がASCIIの記号と同じ値になる文字があります。「ソ」は 83 5C、「表」は 95 5C で、5C はバックスラッシュ(\)の値です。「値ひとつ」の規則では %83%5C のように両方のバイトを %XX にしますが、「URL全体」の規則はURL標準のクエリ用の集合を使い、この集合は \ を変換しないため、%83\ のように2バイト目が記号のまま残ります。Shift_JISの値をUTF-8でデコードすると、バイトが合わず�が出ます。このツールの自動判別は、まずUTF-8として読み、失敗したらEUC-KR・Shift_JIS・Windows-1252として読んだ結果のうち、ありふれた文字が多いものを選びます。反対に、古いサイトへ渡す値を作るときは、文字コードにShift_JISを選びます。Shift_JISにない文字(絵文字など)は、ブラウザのフォームと同じく &#番号; をエンコードした %26%23番号%3B の形で書きます。
日本語ドメインはPunycodeに変換されます
ドメイン(ホスト)にはパーセントエンコーディングを使いません。日本語ドメインは、国際化ドメイン名の規則(IDNA)に従い、xn-- で始まるASCIIの名前(Punycode、RFC 3492)に変換されます。URL全体の規則はホストだけをこの形にし、パスとクエリの日本語は %XX にします。デコードでは xn-- の名前を日本語に戻して表示します。
| ドメイン | Punycode |
|---|---|
| 日本語.jp | xn--wgv71a119e.jp |
| 例え.jp | xn--r8jz45g.jp |
| münchen.de | xn--mnchen-3ya.de |
| 한글.한국 | xn--bj0bj06e.xn--3e0b707e |
コードで行うとき
// JavaScript
encodeURIComponent('日本語 & C++'); // %E6%97%A5%E6%9C%AC%E8%AA%9E%20%26%20C%2B%2B
decodeURIComponent('%E6%97%A5%E6%9C%AC%E8%AA%9E'); // 日本語 (不正な%があるとURIError)
new URLSearchParams({ q: '東京 ラーメン' }).toString(); // q=%E6%9D%B1%E4%BA%AC+%E3%83%A9%E3%83%BC%E3%83%A1%E3%83%B3
new URL('https://日本語.jp/案内').href; // https://xn--wgv71a119e.jp/%E6%A1%88%E5%86%85
# Python
from urllib.parse import quote, quote_plus, unquote, urlencode
quote('日本語 文書', safe='') # %E6%97%A5%E6%9C%AC%E8%AA%9E%20%E6%96%87%E6%9B%B8
quote_plus('日本語 文書') # %E6%97%A5%E6%9C%AC%E8%AA%9E+%E6%96%87%E6%9B%B8
unquote('%93%FA%96%7B%8C%EA', encoding='cp932') # 日本語 (Shift_JIS)
urlencode({'q': '東京 ラーメン', 'page': 2}) # q=%E6%9D%B1%E4%BA%AC+%E3%83%A9%E3%83%BC%E3%83%A1%E3%83%B3&page=2
// PHP
rawurlencode('日本語 文書'); // %E6%97%A5%E6%9C%AC%E8%AA%9E%20%E6%96%87%E6%9B%B8
urlencode('日本語 文書'); // %E6%97%A5%E6%9C%AC%E8%AA%9E+%E6%96%87%E6%9B%B8
http_build_query(['q' => '東京 ラーメン', 'page' => 2]);
// Java
URLEncoder.encode("日本語 文書", StandardCharsets.UTF_8); // %E6%97%A5%E6%9C%AC%E8%AA%9E+%E6%96%87%E6%9B%B8
URLDecoder.decode("%E6%97%A5+%E6%9C%AC", StandardCharsets.UTF_8); // 日 本
フォーム規則の関数(URLSearchParams、Pythonの quote_plus()、PHPの urlencode()、Javaの URLEncoder)は空白を + と書くので、パスに入れる値や署名用の値には、%20 を出す関数を使います。
よくある間違い
- URL全体を値ひとつの規則で変換した場合:
https%3A%2F%2F…になってリンクとして開けません。URLそのものを直すときはURL全体の規則を、別のURLの値として入れるときだけ値ひとつの規則を使います。 - 値の中の&や#をそのまま残した場合: 「A&B」はAだけが渡され、#以降はサーバーへ送られません。値ひとつの規則で
A%26B、%23にします。 - C++が「C」と空白2つになった場合: フォームの規則でデコードする側に
+をそのまま入れたためです。C%2B%2Bと書きます。 - %2520のように二重にエンコードした場合: ライブラリがすでにエンコードする値を、自分でもう一度変換したことが多いです。どの段階でエンコードするかを1か所に決めます。
- Shift_JISの値をUTF-8でデコードした場合: 文字化けしたり�が出たりします。文字コードをShift_JISにしてデコードします。
- decodeURIComponentが止まった場合: 「100%」のように%の後ろに16進数2桁がないと、
URIErrorで止まります。このツールは、そうした%をそのまま残して位置を知らせます。
制限
- 文字を変換する計算だけを行います。URLが実際に開けるか、安全なURLかは確認せず、URLへアクセスもしません。
- URL全体の規則は、URL Standardの構成要素ごとの集合だけを適用します。ブラウザが合わせて行う整理(スキームとホストの小文字化、
../の解決、既定ポートの削除、空のパスへの / の補完)は行いません。Chrome 151はパスの|も%7Cに変換するなど、ブラウザによって数個の記号が異なることがあります。 - mailto: のようなhttp・https以外のURLも、パスの集合で変換します。こうしたURLのパスに対するURL Standardの規則(不透明パス)とは、空白の扱いが異なることがあります。
- 自動判別は推測です。短い値やまれな文字(半角カナなど)は別の文字コードとして読むことがあるので、結果がおかしいときは自分で選んでください。古い文字コードはEUC-KR・Shift_JIS・Windows-1252だけを扱い、EUC-JPやBig5などは扱いません。
- URL分解は読み取りとコピーだけを行います。クエリの項目を直したり追加したりするときは、URLクエリ ↔ 項目表 ツールを使ってください。言語・関数ごとの結果は、元の文字列の先頭4,000文字までを比較します。
基準日: エンコードの集合はURL Standard(2026年10月19日版)とRFC 3986、署名の規則はRFC 5849とAWSのドキュメント、関数の動作は各言語のドキュメントを、2026年10月22日に確認しました。表の値は、このツールとPHP 8.5・Python 3.14・Node.js 26・Chromium 151で同じ結果になることを確認しています。
出典
- 01WHATWG: URL Standard, Percent-encoded bytesfragment・query・special-query・path・userinfo・component・フォームの各集合、古い文字コードと &#番号; の扱い
- 02WHATWG: application/x-www-form-urlencodedフォームのシリアライズ(空白 → +)とデコード(+ → 空白)
- 03RFC 3986: Uniform Resource Identifier (URI): Generic Syntax2.1 大文字の16進数、2.2 予約文字、2.3 非予約文字、2.4 二重エンコード禁止、2.5 UTF-8、付録B 正規表現
- 04ECMAScript: URI Handling FunctionsencodeURI・encodeURIComponent・decodeURIComponent の定義
- 05MDN: encodeURIComponent()そのまま残す文字、対になっていないサロゲートのURIError
- 06RFC 5849 3.6: OAuth 1.0 Percent Encoding非予約文字だけを残し、ほかは大文字の16進数にする
- 07AWS: Create a signed AWS API requestUriEncode: 非予約文字だけを残し、空白は %20、16進数は大文字
- 08PHP: urlencode-_. 以外をすべて変換し、空白は +。RFC 3986方式は rawurlencode
- 09Python: urllib.parse.quote_.-~ はそのまま、safe の既定値は '/'、quote_plus は空白を +
- 10Java: URLEncoder. - * _ はそのまま、空白は +、UTF-8を推奨
- 11RFC 3492: Punycode国際化ドメイン名の xn-- 形式
- 12WHATWG: Encoding StandardEUC-KR(CP949拡張を含む)・Shift_JIS・Windows-1252 の解釈
よくある質問
URLエンコードとデコードとは何ですか?
URLにそのまま使えない文字を、バイトごとに%と16進数2桁で書くのがURLエンコードで、その表記を元の文字に戻すのがデコードです。「日」はUTF-8で3バイトなので%E6%97%A5になり、デコードすると「日」に戻ります。暗号化ではなく表記の方式なので、誰でも元に戻せます。
encodeURIとencodeURIComponentは何が違いますか?
encodeURIComponentは値ひとつに使う関数で、& = / ? # : などの区切り記号まで変換します。encodeURIはURL全体に使う関数で、それらの記号を残します。そのため、検索語「A&B」をencodeURIで変換すると&が残り、値が2つに分かれてしまいます。また、encodeURIはすでにある%20も%2520に変換するので、URL全体にはこのツールの「URL全体」の規則(URL Standard)のほうが安全です。
空白は%20ですか、それとも+ですか?
どちらも使われます。パスやほとんどの値では%20で、HTMLフォーム送信とURLSearchParamsは空白を+と書きます。デコードでも、decodeURIComponent・PHPのrawurldecode・Pythonのunquoteは+をそのまま残し、URLSearchParams・PHPのurldecode・Pythonのunquote_plusは空白として読みます。本物のプラスを%2B、空白を%20と書けば、どこでも混乱しません。
%が%25に変わって%2520のようになるのはなぜですか?
エンコード済みの文字列をもう一度エンコードしたからです。%はエンコードの目印なので、文字としての%は%25になり、%20が%2520になります。RFC 3986も、同じ文字列を二重にエンコードしたり二重にデコードしたりしないよう定めています。エンコードの欄に貼った値に%25が見えるときは、「もう一段デコード」ボタンで一段ずつ戻せます。
デコードしたら文字化けしたり�が出たりします。
UTF-8以外の文字コードで作られた値の可能性が高いです。古い日本のサイトはShift_JIS(CP932)で「日本語」を%93%FA%96%7B%8C%EAと書いており、これをUTF-8として読むと文字化けします。このツールは、UTF-8で読めないときにEUC-KR・Shift_JIS・Windows-1252のうち合うものを選んで読み、文字コードの欄で手動で選ぶこともできます。
日本語ドメインも%でエンコードしますか?
いいえ。ドメインにはパーセントエンコーディングを使わず、Punycodeに変換したxn--で始まるASCIIの名前を使います。日本語.jpはxn--wgv71a119e.jpになります。「URL全体」の規則はドメインだけをPunycodeに変換し、パスとクエリの日本語は%XXに変換します。
別のURLをクエリの値として入れるにはどうしますか?
内側のURLを「値ひとつ」の規則でまるごとエンコードして付けます。https://b.com/?x=1&y=2はhttps%3A%2F%2Fb.com%2F%3Fx%3D1%26y%3D2になり、外側のURLのredirect=の後ろに入れても、& ? #が外側の区切り記号として読まれません。URL分解では、値の中のURLを見つけて「このURLをデコード」でもう一度展開できます。
入力したURLはサーバーに送信されますか?
いいえ。エンコード・デコード・URL分解・ドメイン変換はすべてこのブラウザの中で計算し、入力した文字列をサーバーに送信も保存もせず、ページのURLにも残しません。URLにパスワードやトークンが含まれていても、このページの外には出ません。