Edited at

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

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");
}