⚔️

「天安門」禁止フィルタが「天安⾨」なら通る話

2020/09/29に公開

概要

ネットゲームでよくある、名前やプロフィール欄に入力できない禁止ワード。
おおむね初期の実装は簡素なもので、異体字を使うと通ってしまう。

天安門

を例にした場合

天安⾨

ならフィルタに引っかからず大丈夫。

これは「門」の部分が「門(u9580)」ではなく「⾨(u2fa8)」という別の文字になっており、通常の「天安門」では文字列の検索でヒットしなくなってしまうため。

解決するには

では、これらはどうやって解決すればよいのか。

さまざま手段はあるが、一例として正規表現での解決を記す。

正規表現で対応する例

正規表現では一致させたいキーワードを複数パターン持つことができる。

例えば、「えび」と「いくら」を一致させたい場合

(えび|いくら)

と書くことで、両方に一致させることができる。

天安門も同様に

(天安門|天安⾨)

とすることで、問題を回避できる。

と思った?残念!

では「天安門」でも「天安⾨」でもなく、「㆝安門」ならどうだろうか?

ダメ。

これは、今度は「天」の文字が「天(u5929)」ではなく「㆝(u319d)」となっている。

いたちごっこの始まりである。

さらに、正規表現で対応する例

ではどう対応するか、正規表現では一文字単位で複数のキーワードを持つことができる。

例えば、「最高」と「最低」を一致させたい場合

最[高低]

と書くことで、両方に一致させることができる。

つまり天安門は

[天㆝]安[門⾨]

と書くことで異体字に対応できる。

やった!解決!と思った?

異体字でのフィルタ回避は問題の一例であり、その他にもフィルタの回避方法は存在する。
(パッと説明できる物が思いつかないのでここには書かないでおく)
新たな回避策にどう対応するか、さまざまな知識が必要となる。

そして、その問題への調査・対応には膨大な人的コストが必要となってくる。

正規表現について

正規表現、めちゃくちゃおもしろいので勉強すると楽しいですよ。
お仕事でめちゃくちゃ活躍します。

参考:
正規表現のサンプル一覧
正規表現チェッカー

後日談 (2020/09/30 追記)

Unicode正規化を使えばいい、とコメントをもらう。

何これ!ズルい!

みんなも Chrome で F12 → Esc と押して出てきた Console 欄に以下を入力して試してみよう!

"天安⾨".match(/天安門/)
"天安⾨".normalize('NFKC').match(/天安門/)

参考:
String.prototype.normalize() - JavaScript | MDN
正規化形式別のユニコード正規化の振る舞いの違いを見てみる | 分析ノート

GitHubで編集を提案

Discussion