Java

ユーザー名を正規表現でチェックする

More than 3 years have passed since last update.

ゲームのユーザー名のチェック処理として適切な正規表現を考えてみる。
結論、これで事足りると思う。

Pattern.compile("[^0-9a-zA-Zぁ-んァ-ヶ一-龠々ー]");

文字の種類

考慮すべき文字種の多すぎてまとめきれる気がしない。

  • 全角ひらがな "あいうえお"
  • 全角カタカナ "アイウエオ"
  • 半角カタカナ "アイウエオ"
  • 全角数字 "12345"
  • 半角数字 "12345"
  • 全角英字大文字 "ABCDE"
  • 全角英字小文字 "abcde"
  • 半角英字大文字 "ABCDE"
  • 半角英字小文字 "abcde"
  • 全角記号 "!#$%&"
  • 半角記号 "!#$%&"
  • 漢字 "亜異兎絵尾"
  • 長音 "ー"
  • 中点 "・"
  • 繰り返し記号 "〃ゝゞヽヾ"
  • 機種依存文字 "①②③④⑤"
  • キリル文字大文字 "АБВГҐ"
  • キリル文字小文字 "абвгґ"
  • ハングル "아가다오쓰"
  • アラビア "غة العرب"

仕様の決め方

UI上の良し悪し(特に視認性)や、ゲームの世界観を判断材料にして決める。

  • 顔文字はNGにしたい (・∀・)
    • 括弧をNGにすればよさそう
  • ユーザー名に句点・読点はなしだと思う
    • じゃあ「モーニング娘。」みたいのもNG?
  • 日本と馴染みの薄い言語の文字はNGにしたい
    • 簡体字・繁体字・ハングル・ロシア・アラビア
    • RMT業者との戦いの歴史があるMMORPGでは特に中国語の印象よくない
  • †聖天使猫姫†みたいな痛ネームは許容すべきか

簡体字と繁体字の除外

日本で使われてる漢字と、簡体字/繁体字は、文字コードのなかでゴチャマゼにないっているため、"一-龠"のような範囲指定では除外不可能。
一般的なゲームでも簡体字/繁体字を除外してるケースは少ないと思われる。
要件的にどうしても除外しなければいけないのなら、簡体字/繁体字テーブルのようなものを作って除外していくしかなさそう。

コード

public class NameChecker {

    private static final String P_STR = "[^0-9a-zA-Zぁ-んァ-ヶ一-龠々ー]"
    private static final Pattern P_NAME = Pattern.compile(P_STR);

    // チェック処理
    public static void check(String name) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0, len = name.length(); i < len; i++) {
            String s = name.substring(i, i + 1);
            if (isMatch(s)) {
                sb.append(s);
            }
        }
        print(name, sb);
    }

    public static boolean isMatch(String s) {
        Matcher matcher = P_NAME.matcher(s);
        return matcher.find();
    }

    private static void print(String name, StringBuilder sb) {
        if (sb.length() == 0) {
            System.out.printf("OK: %s%n", name);
        } else {
            System.out.printf("NG: %d/%d %s [%s]%n", sb.length(), name.length(), name, sb.toString());
        }
    }

    // テストコード
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        // 半角数字
        check("0123456789");
        // 半角英小文字
        check("abcdefghijklmnopqrstuvwxyz");
        // 半角英大文字
        check("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        // 全角ひらがな
        check("あいうえお");
        check("かきくけこ");
        check("さしすせそ");
        check("たちつてと");
        check("なにぬねの");
        check("はひふへほ");
        check("まみむめも");
        check("やゆよ");
        check("らりるれろ");
        check("わゐうゑをん");
        check("がぎぐげご");
        check("ざじずぜぞ");
        check("だぢづでど");
        check("ばびぶべぼ");
        check("ぱぴぷぺぽ");
        // 全角ひらがな小文字
        check("ぁぃぅぇぉ");
        check("ゃゅょ");
        // 全角カタカナ
        check("アイウエオ");
        check("カキクケコ");
        check("サシスセソ");
        check("タチツテト");
        check("ナニヌネノ");
        check("ハヒフヘホ");
        check("マミムメモ");
        check("ヤユヨ");
        check("ラリルレロ");
        check("ワヰウヱヲンヴ");
        check("カギグゲゴ");
        check("ザジズゼゾ");
        check("ダヂヅデド");
        check("バビブベボ");
        check("パピプペポ");
        // 全角カタカナ小文字
        check("ァィゥェォ");
        check("ャュョ");
        check("ヶ");
        // 音引き
        check("ー");
        // 漢字
        check("亜々赤白憂鬱幽霊");
        check("嘉緒翠京桜靖ビス湖とっぽ束生夏陽夏照空々");
        check("神生理美依羅炎皇斗幻の銀侍沙利菜愛利江留");
        check("野風平蔵重親愛海月夢杏一将来織田信長");
        check("邪王炎殺黒龍波");
        // 簡体字
        check("北京微梦创科网络技术有限公司");
        check("对写处圆");
        // 繁体字
        check("亞假勛龍龜");
        check("世棒經典賽王建民媽媽嘴大樂透劉真莫那魯道壽司");

        System.out.println("---------- 以下NG ----------");

        // 全角数字
        check("0123456789");
        // 全角英小文字
        check("abcdefghijklmnopqrstuvwxyz");
        // 全角英大文字
        check("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        // 半角カタカナ
        check("ァィゥェォ");
        check("カキクケコ");
        check("サシスセソ");
        check("タチツテト");
        check("ナニヌネノ");
        check("ハヒフヘホ");
        check("マミムメモ");
        check("ヤユヨ");
        // 中黒
        check("・");
        // 濁音、半濁音
        check("゜゛");
        // 空白
        check("   ");
        // 記号
        check("!#$%&*+,-.:;=?@^_`|~");
        check("!#$%&()*+,.―/ 0-9:;<=>?@A-Z[]^_`a-z{|} ̄");
        check("()[]{}<>");
        check("\"'");
        check("\\");
        check("○△□◇◎●▲■◆");
        check("~~");
        check("--");
        check("♪♫♬");
        check("※〒¶");
        check("…‥。、∴∵,.");
        check("↑→↓←⇐⇒⇔");
        // 繰り返し記号
        check("〃ゝゞヽヾ");
        // 機種依存文字
        check("①②③④⑤⑥⑦⑧⑨⑩");
        // 特殊文字
        check("†聖天使猫姫†");
        // ハングル
        check("아가다오쓰나는");
        // キリル文字
        check("АБВГҐДЃЂЕЄЀЁЖЗЅИІЇЙЍЈКЛЉМНЊОӨПРСТ");
        check("абвгґдѓђеєѐёжзѕиіїйѝјклљмнњоөпрст");
        // アラビア語
        check("غة العربي");

        System.out.println((System.currentTimeMillis() - start) + "ms");
    }