PHP Tips | 文字列処理:ログ・表示向け - 伏字変換

PHP PHP
スポンサーリンク

「伏字変換」で何をしたいのか

伏字変換は、「文字列の一部を別の文字(*や●など)に置き換える」ことです。
目的はだいたい 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);
// **とか**とか言わない
PHP

NG ワードが含まれている部分だけが、きれいに伏字になっています。

複数回出てくる場合

echo censor_words('バカバカ言うなよバカ', $ngWords);
// ****言うなよ**
PHP

str_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

もし、あなたのプロジェクトで「ユーザー入力をそのまま画面やログに出している」箇所があれば、
そこがこの伏字変換ユーティリティを差し込むベストポイントです。
たった数行の前処理で、「見せ方の安全性」と「読みやすさ」を同時に底上げできます。

タイトルとURLをコピーしました