「伏字変換」で何をしたいのか
伏字変換は、「文字列の一部を別の文字(*や●など)に置き換える」ことです。
目的はだいたい 2 つあります。
1つ目は「見せたくない情報を隠す」こと。
NG ワード、暴言、機密情報などを、そのまま画面やログに出したくないときに使います。
2つ目は「文脈は残したまま、きつさを和らげる」こと。
たとえば、ユーザーが書いたコメントをそのまま表示するとき、
完全に削除するのではなく、問題のある単語だけ伏字にする、という使い方です。
伏字変換の基本方針を決める
「何を」「どう」伏字にするか
伏字変換には、最低限この 2 つを決める必要があります。
どの単語・パターンを伏字にするか。
伏字にするとき、何文字で置き換えるか。
例えば、NG ワードリストがこうだとします。
- 「死ね」
- 「バカ」
これを、次のように変換したいとします。
「死ねよ」 → 「**よ」
「バカだな」 → 「**だな」
ここでは、「NG ワードの文字数と同じ数の伏字文字(*)で置き換える」というルールにします。
こうしておくと、「どこが伏字になったか」が分かりやすく、文のリズムもあまり崩れません。
コアとなる伏字変換関数を作る
NG ワードリストをもとに置き換える
まずは、シンプルに「完全一致する単語を伏字にする」関数を作ります。
/**
* NG ワードを伏字(*)に置き換える
*
* @param string $text 元のテキスト
* @param string[] $ngWords NG ワードの配列
*/
function censor_words(string $text, array $ngWords): string
{
foreach ($ngWords as $word) {
if ($word === '') {
continue;
}
$len = mb_strlen($word, 'UTF-8');
// NG ワードと同じ長さの * を作る
$mask = str_repeat('*', $len);
// その単語を全部伏字に置き換える
$text = str_replace($word, $mask, $text);
}
return $text;
}
PHPここでの重要ポイントは 2 つです。
1つ目は、mb_strlen を使って「文字数ベース」で長さを数えていること。
日本語は 1 文字が 1 バイトとは限らないので、マルチバイト対応が必須です。
2つ目は、「NG ワードと同じ長さの伏字を作る」こと。
これで、「どの部分が伏字になったか」が直感的に分かります。
例題で挙動を確認する
シンプルな例
$ngWords = ['死ね', 'バカ'];
echo censor_words('死ねよ', $ngWords);
// **よ
echo censor_words('お前バカだな', $ngWords);
// お前**だな
echo censor_words('死ねとかバカとか言わない', $ngWords);
// **とか**とか言わない
PHPNG ワードが含まれている部分だけが、きれいに伏字になっています。
複数回出てくる場合
echo censor_words('バカバカ言うなよバカ', $ngWords);
// ****言うなよ**
PHPstr_replace は「全部置き換える」ので、
同じ NG ワードが何回出てきても、すべて伏字になります。
もう一歩:大文字・小文字や全角・半角を吸収したい場合
英字の NG ワード(case-insensitive)
英字の NG ワードを扱うとき、「大文字・小文字を区別しない」ほうが自然なことが多いです。
"bad" を NG ワードにしたら、"Bad", "BAD" も伏字にしたい、というケースです。
その場合は、str_ireplace(大文字小文字を区別しない置き換え)を使います。
function censor_words_case_insensitive(string $text, array $ngWords): string
{
foreach ($ngWords as $word) {
if ($word === '') {
continue;
}
$len = mb_strlen($word, 'UTF-8');
$mask = str_repeat('*', $len);
$text = str_ireplace($word, $mask, $text);
}
return $text;
}
PHP全角・半角をそろえてから伏字にする
日本語環境では、「バカ」「バカ」「ばか」など、
表記ゆれが多いです。
厳密にやるなら、伏字変換の前に「全角・半角・ひらがな・カタカナ」をそろえる前処理を入れます。
function normalize_for_censor(string $text): string
{
// 全角英数字 → 半角、ひらがな → カタカナ など
return mb_convert_kana($text, 'asKV', 'UTF-8');
}
PHPそして、
$textNorm = normalize_for_censor($text);
$ngNorm = array_map('normalize_for_censor', $ngWords);
PHPのように、「同じルールで正規化したもの同士」で伏字判定をする、という設計もできます。
ここまでやると少し高度なので、「必要になったら足す」くらいの感覚で大丈夫です。
実務での使いどころ
ユーザーコメントの表示前に伏字をかける
掲示板やコメント機能で、
「投稿自体は通すが、NG ワードだけ伏字にしたい」というケースです。
$ngWords = ['死ね', 'バカ'];
$rawComment = $_POST['comment'] ?? '';
$displayComment = censor_words($rawComment, $ngWords);
echo nl2br(htmlspecialchars($displayComment, ENT_QUOTES, 'UTF-8'));
PHPここでの重要ポイントは、「伏字変換 → HTML エスケープ」の順番です。
伏字変換はプレーンテキスト上で行い、そのあとで htmlspecialchars で画面表示用に変換します。
ログ出力時に一部だけ伏字にする
ログにユーザー入力を残したいが、
NG ワードはそのまま残したくない、という場合にも使えます。
$ngWords = ['死ね', 'バカ'];
$rawComment = $_POST['comment'] ?? '';
$logComment = censor_words($rawComment, $ngWords);
error_log('comment=' . $logComment);
PHPログを見れば「どんな雰囲気のコメントか」は分かりますが、
直接的な表現は伏字になっている、という状態を作れます。
伏字変換の「限界」と付き合い方
伏字変換は便利ですが、「万能ではない」ということも大事です。
NG ワードリストにない表現は当然すり抜けます。
文字を少し変えた表現(例:バーカ、しね、バカ)も、ルール次第ではすり抜けます。
だからこそ、「伏字変換だけで完璧にフィルタする」のではなく、
最低限のマナー違反を和らげる。
ログや画面にそのまま出したくない単語を隠す。
くらいの役割として位置づけておくのが現実的です。
まとめ:今日からの「伏字変換」ユーティリティ
伏字変換の本質は、「特定の単語だけを、同じ長さの伏字文字に置き換える」ことです。
そのために、
NG ワードリストを用意する。
各 NG ワードの長さを数え、その長さ分の伏字文字を作る。str_replace(または str_ireplace)で一括置き換えする。
という流れをユーティリティ関数に閉じ込めます。
もう一度、基本形を載せておきます。
function censor_words(string $text, array $ngWords): string
{
foreach ($ngWords as $word) {
if ($word === '') {
continue;
}
$len = mb_strlen($word, 'UTF-8');
$mask = str_repeat('*', $len);
$text = str_replace($word, $mask, $text);
}
return $text;
}
PHPもし、あなたのプロジェクトで「ユーザー入力をそのまま画面やログに出している」箇所があれば、
そこがこの伏字変換ユーティリティを差し込むベストポイントです。
たった数行の前処理で、「見せ方の安全性」と「読みやすさ」を同時に底上げできます。
