「単語境界のみ置換」って何をしたいのか
まず、やりたいことのイメージからいきます。
「単語境界のみ置換」は、こういうニーズです。
「cat という単語だけを dog に置き換えたい。
でも、category の中の cat までは置き換えたくない。」
具体的にはこうです。
元の文字列:
"I have a cat. This category is about cats."
やりたいこと:
"cat" という「単語」だけを "dog" に置き換えたい。
結果:
"I have a dog. This category is about cats."
ここで重要なのは、
cat→dogに置き換えたい- でも
categoryの中のcatはそのままにしたい
という「単語としての境界」を意識した置換です。
普通の str_replace('cat', 'dog', ...) を使うと、category の中の cat まで全部置き換わってしまいます。
そこで出てくるのが「単語境界」を扱える正規表現置換です。
なぜ str_replace ではダメなのか
str_replace は「部分一致」さえしていれば、容赦なく置き換えます。
$text = "I have a cat. This category is about cats.";
$result = str_replace("cat", "dog", $text);
echo $result;
// I have a dog. This dogegory is about dogs.
PHP見ての通り、
cat→dogcategoryの中のcat→dogegorycatsの中のcat→dogs
と、「単語としての cat」だけでなく、
他の単語の一部まで全部変わってしまいます。
「単語としての cat だけを置き換えたい」場合には、str_replace では制御できません。
ここで「単語境界」を理解している正規表現の出番になります。
正規表現の「単語境界」\b を使う
\b の意味
正規表現には \b という「単語境界」を表すメタ文字があります。
ざっくり言うと、
「単語文字(英数字やアンダースコア)と、それ以外の境目」
の位置にマッチします。
例えば、"cat" という単語に対して、
" cat "の前後"cat."の後ろ"cat,"の後ろ
など、「単語として区切られている位置」に \b がマッチします。
逆に、"category" の中の cat の前後は、
どちらも「単語文字同士」なので、そこには \b はありません。
この性質を使って、
「単語としての
catだけにマッチするパターン」
を作ります。
パターン:\bcat\b
$text = "I have a cat. This category is about cats.";
$result = preg_replace('/\bcat\b/', 'dog', $text);
echo $result;
// I have a dog. This category is about cats.
PHPパターン /\bcat\b/ を分解すると、
\b:単語境界cat:文字列 “cat”\b:単語境界
つまり、「前後が単語境界になっている cat」だけにマッチします。
その結果、
" cat."の中のcat→ 前後が境界なのでマッチ →dogに置換"category"の中のcat→ 前後が単語文字なのでマッチしない → そのまま"cats"の中のcat→ 後ろがs(単語文字)なのでマッチしない → そのまま
となります。
これが「単語境界のみ置換」の基本パターンです。
大文字小文字を無視して単語境界置換する
“Cat” も “CAT” もまとめて置換したい
英語の文章では、先頭だけ大文字になっていることも多いです。
$text = "Cat and cat and CAT are all here.";
PHPこれに対して、「単語としての cat を全部 dog にしたい」なら、
大文字小文字も無視したいですよね。
その場合は、正規表現の i フラグ(ignore case)を使います。
$text = "Cat and cat and CAT are all here.";
$result = preg_replace('/\bcat\b/i', 'dog', $text);
echo $result;
// dog and dog and dog are all here.
PHP/...\b/i の i が「大文字小文字を無視する」指定です。
ここでの重要ポイントは、
「単語境界」と「大文字小文字無視」を組み合わせると、
単語としてのcatを、表記ゆれごと一気に置換できる
ということです。
実務での使いどころ
NGワードを「単語として」だけマスクしたい
例えば、NGワード "bad" をマスクしたいとします。
$text = "This is a bad example of a badge.";
PHPstr_replace("bad", "***", ...) を使うと、
// This is a *** example of a ***ge.
PHPとなり、badge の中の bad までマスクされてしまいます。
単語としての "bad" だけをマスクしたいなら、こうします。
$result = preg_replace('/\bbad\b/i', '***', $text);
echo $result;
// This is a *** example of a badge.
PHPこれなら、"bad" だけがマスクされ、"badge" はそのままです。
コマンドやキーワードだけを置換したい
ログやスクリプトの中で、特定のコマンド名だけを置換したいときにも使えます。
$text = "run task1; rerun task1; task10 is different.";
$result = preg_replace('/\btask1\b/', 'taskX', $text);
echo $result;
// run taskX; rerun taskX; task10 is different.
PHPtask10 の中の task1 は単語境界ではないので、そのまま残ります。
ユーティリティ関数としてまとめる
単語境界置換のラッパー
毎回パターンを書くのが面倒なら、
「単語としての置換」をするユーティリティ関数にしてしまうと便利です。
/**
* 単語境界のみ置換(大文字小文字を区別する)
*/
function replaceWord(string $word, string $replacement, string $text): string
{
$pattern = '/\b' . preg_quote($word, '/') . '\b/';
return preg_replace($pattern, $replacement, $text);
}
PHPここでの preg_quote($word, '/') は、$word の中に . や + などの正規表現の記号が入っていても、
「ただの文字」として扱えるようにエスケープしてくれます。
使い方はこうです。
$text = "I have a cat. This category is about cats.";
echo replaceWord('cat', 'dog', $text);
// I have a dog. This category is about cats.
PHP大文字小文字を無視する版
/**
* 単語境界のみ置換(大文字小文字を無視)
*/
function replaceWordIgnoreCase(string $word, string $replacement, string $text): string
{
$pattern = '/\b' . preg_quote($word, '/') . '\b/i';
return preg_replace($pattern, $replacement, $text);
}
PHP$text = "Cat and cat and CAT are all here.";
echo replaceWordIgnoreCase('cat', 'dog', $text);
// dog and dog and dog are all here.
PHP「単語としての置換」を関数名にしておくことで、
呼び出し側のコードを読んだときに意図がすぐ伝わります。
日本語と「単語境界」の注意点
ここは少しだけ重要な補足です。
\b の「単語境界」は、
基本的に「英数字とアンダースコア」を「単語文字」として扱います。
日本語(ひらがな・カタカナ・漢字)は、\b の対象外になることが多いです。
つまり、
$text = "ねこ と 猫cat がいます。";
preg_replace('/\bcat\b/', 'dog', $text);
PHPのような場合は、cat の前後が英数字ではないので、\b の挙動が直感とズレることがあります。
日本語を含むテキストで「単語境界」を厳密に扱いたい場合は、
- スペースや句読点で区切る
- 自分で「境界条件」を正規表現で書く(例:
(^|[\s、。])cat($|[\s、。]))
など、もう一段工夫が必要になります。
英字だけの単語を対象にするなら、\b で十分です。
まとめ:今日からの「単語境界のみ置換」ユーティリティ
押さえておきたいポイントをコンパクトにまとめます。
単語境界のみ置換は、
str_replaceだと「単語の一部」まで置き換わってしまう問題を避けるためのテクニック。- 正規表現の
\b(単語境界)を使って、/\bword\b/のようなパターンで「単語としての word」だけにマッチさせる。 - 大文字小文字を無視したいときは、
/\bword\b/iのようにiフラグを付ける。 - 実務では、NGワードマスク、コマンド名の置換、英単語の表記ゆれ修正などでよく使える。
