何をしたいユーティリティか:「スラッグ生成」
ここでの「スラッグ生成」は、人間が読めて、URL や識別子としても扱いやすい「きれいな文字列」を作ることです。
ブログ記事の URL、商品ページのパス、カテゴリコードなどでよく使われます。
例えば、こんな変換をしたいイメージです。
"はじめての JavaScript 入門"→"hajimete-no-javascript-nyumon"" Hello, World! "→"hello-world""商品#123_特価!!"→"shang-pin-123-te-jia"(ローマ字化や簡略化の方針次第)
ここでは、まず「英数字ベースのスラッグ」を作る基本形を押さえ、そのうえで日本語を含む場合の考え方も触れます。
スラッグの基本ルールを決める
どんな文字を許可するか
まず、「スラッグに含めてよい文字」を決めます。
よくあるルールはこんな感じです。
- 小文字の英字
a-z - 数字
0-9 - 区切り用のハイフン
-
それ以外の文字(スペース、記号、日本語など)は、
- 区切り(スペースなど)はハイフンに変換
- それ以外は削除 or ローマ字化
という方針を取ります。
ここではまず、「英数字以外は区切り扱いにしてハイフンにする → 連続ハイフンを 1 個にまとめる → 端のハイフンを削る」というシンプルな版を作ります。
英数字ベースのシンプルなスラッグ生成
基本実装
function slugifyBasic(input) {
if (!input) {
return "";
}
let str = String(input).trim().toLowerCase();
str = str.replace(/[^a-z0-9]+/g, "-");
str = str.replace(/^-+|-+$/g, "");
return str;
}
JavaScript重要なポイントをかみ砕いて説明する
1. 文字列化して、前後の空白を削り、小文字にする
let str = String(input).trim().toLowerCase();
JavaScriptここでやっていることは 3 つです。
String(input)で、数値なども含めて文字列に統一trim()で前後の空白を削除toLowerCase()で小文字に統一
スラッグは「大文字小文字を区別しない」ことが多いので、最初に小文字にしてしまうのが定番です。
2. 英数字以外を「区切り」としてハイフンにする
str = str.replace(/[^a-z0-9]+/g, "-");
JavaScript[^a-z0-9]+ は、「英小文字と数字以外が 1 文字以上続く部分」を意味します。
それを全部 "-" に置き換えています。
つまり、
- スペース
" " - 記号
"!","?",",","_"など - 日本語
"あ","漢"など
は、いったん全部「区切り」とみなして "-" に変わります。
例:
"Hello, World!"→"hello--world-"(この時点ではハイフンが連続したり末尾に付いたりする)
3. 先頭と末尾のハイフンを削る
str = str.replace(/^-+|-+$/g, "");
JavaScript/^-+|-+$/g は、「先頭の連続ハイフン」または「末尾の連続ハイフン」を意味します。
それを空文字に置き換えることで、端の余計なハイフンを削ります。
ただ、このままだと "hello--world" のように「中に連続ハイフン」が残ることがあります。
気になる場合は、もう一段階整形します。
連続ハイフンを 1 個にまとめる改良版
改良した slugify
function slugify(input) {
if (!input) {
return "";
}
let str = String(input).trim().toLowerCase();
str = str.replace(/[^a-z0-9]+/g, "-");
str = str.replace(/-+/g, "-");
str = str.replace(/^-+|-+$/g, "");
return str;
}
JavaScript追加したポイント
str = str.replace(/-+/g, "-");
JavaScriptここで、「連続したハイフン -+ を 1 個の - にまとめる」処理を入れています。
これで、
"Hello, World!"→"hello-world""---A---B---"→"a-b"
のように、スラッグとしてきれいな形になります。
実際の動きを例で確認する
slugify("Hello, World!");
// "hello-world"
slugify(" JavaScript 入門 2024!! ");
// "javascript-2024"(日本語部分は区切り扱いで落ちる)
slugify("商品#123_特価!!");
// "123"(英数字以外は区切り扱い)
JavaScriptこの「英数字以外を全部区切り扱いにする」方針だと、
日本語はすべて落ちてしまいます。
それでもよいケース(内部コード用など)もありますが、
「日本語タイトルからそれっぽいスラッグを作りたい」場合は、もう一歩踏み込みが必要です。
日本語を含むスラッグをどう扱うか
方針を決めるのが一番大事
日本語を含むスラッグについては、ざっくり次のような選択肢があります。
- 日本語をそのまま許可する(URL エンコードに任せる)
- 日本語をローマ字化する
- 日本語部分は捨てて、別の識別子(ID など)を使う
ここでは、シンプルに「日本語も含めて、英数字+ハイフン+日本語を許可する」版を一つ示します。
日本語を残すスラッグ生成(簡易版)
実装例
function slugifyWithJapanese(input) {
if (!input) {
return "";
}
let str = String(input).trim().toLowerCase();
str = str.replace(/[\s_]+/g, "-");
str = str.replace(/[^a-z0-9\u3040-\u30ff\u4e00-\u9faf\-]+/g, "");
str = str.replace(/-+/g, "-");
str = str.replace(/^-+|-+$/g, "");
return str;
}
JavaScript重要ポイント
str = str.replace(/[\s_]+/g, "-");
JavaScriptまず、スペースやアンダースコアを「区切り」としてハイフンに変えています。
str = str.replace(/[^a-z0-9\u3040-\u30ff\u4e00-\u9faf\-]+/g, "");
JavaScriptここで、「許可する文字」以外を削除しています。
a-z0-9→ 英数字\u3040-\u30ff→ ひらがな・カタカナ\u4e00-\u9faf→ CJK 統合漢字(ざっくり漢字)\-→ ハイフン
これに当てはまらない記号などは削除されます。
実際の動き
slugifyWithJapanese("はじめての JavaScript 入門");
// "はじめての-javascript-入門"
slugifyWithJapanese("商品#123_特価!!");
// "商品123-特価"
slugifyWithJapanese(" 令和6年度_売上レポート ");
// "令和6年度-売上レポート"
JavaScriptこのように、「日本語+英数字+ハイフン」で構成されたスラッグが作れます。
URL として使うときは、ブラウザやサーバが自動的にパーセントエンコードしてくれます。
実務で意識してほしい設計のポイント
「スラッグの仕様」を先に決める
スラッグは、あとから仕様変更が入りやすい部分です。
- 英数字だけにしたいのか
- 日本語を許可するのか
- 大文字小文字を区別するのか
- 最大長をどれくらいにするのか
これを曖昧にしたまま使い始めると、
途中で「やっぱり日本語も残したい」「やっぱり英数字だけにしたい」となって、
既存データとの整合性が大変になります。
だからこそ、ユーティリティを作るタイミングで、
「このプロジェクトのスラッグはこういうルールで作る」
と決めておくのが重要です。
「表示用」と「内部識別子」を分ける
スラッグは「人間が読む URL の一部」として使われることが多いですが、
DB の主キーや内部識別子としては、別の ID(数値 ID や UUID)を使うのが安全です。
URL 例:
/articles/12345-hajimete-no-javascript-nyumon
ここで、
12345→ 内部の記事 ID(DB の主キー)hajimete-no-javascript-nyumon→ 表示用スラッグ
という分担にしておけば、
スラッグの仕様を変えたくなっても、ID さえ変わらなければリンクは生き続けます。
スラッグの一意性は別で担保する
スラッグ生成ユーティリティは、「同じ入力から同じスラッグを作る」ことはできますが、
「全体で一意かどうか」は保証しません。
"JavaScript 入門" → "javascript-nyumon""JavaScript 入門(改訂版)" → "javascript-nyumon"(同じになる可能性)
このような場合は、
- 末尾に ID を付ける(
"javascript-nyumon-12345") - 既存スラッグと重複していたら
-2,-3を付ける
などのロジックを、アプリ側で追加する必要があります。
少し手を動かして感覚をつかむ
コンソールで、次のようなコードを実際に打ってみてください。
slugify("Hello, World!");
slugify(" JavaScript 入門 2024!! ");
slugify("商品#123_特価!!");
slugifyWithJapanese("はじめての JavaScript 入門");
slugifyWithJapanese("商品#123_特価!!");
slugifyWithJapanese(" 令和6年度_売上レポート ");
JavaScriptどの文字が残り、どの文字がハイフンになり、どの文字が削除されるかを、
自分の目で確認してみてください。
そのうえで、自分のプロジェクトに
export function slugify(...) { ... }
export function slugifyWithJapanese(...) { ... }
JavaScriptのような関数を置き、
「URL やコード用のスラッグが欲しくなったら、必ずこの“スラッグ生成ユーティリティ”を通す」
というルールを作ってみてください。
それだけで、あなたのシステムのスラッグは、場当たり的な置換の寄せ集めから、
意図と一貫性を備えた「業務レベルのスラッグ生成」に変わっていきます。
