2007年10月14日日曜日

電話番号の正規表現.

 今まで下らないと思って見てこなかったアルマゲドン.
 …不覚にも泣いてしまった orz
 あんな茶番劇に…自分で自分が情けない.

 と言うどーでもいい話に続いて、更にどーでもいい話をw
 電話番号の正規表現.
 検索かけると色々と出てきますが、心底意外にもその殆んどが怪しげな正規表現で「え〜…それじゃ抜け落ちるじゃん」と言う様な物でした.
 何で??
 みんな使う機会が多いと思うんだけどなぁ.

 勿論中には

 二度目の公開!電話番号の正規表現

 と言う様な素晴らしい正規表現も見付かりました.
 んが、そんなゴッツイ正規表現を求めるつもりは無い私の様な適当人間は、↓こんなんで十分だと思います.

public class Formatter {
    /**
     * Constructor.
     */
    public Formatter() {
    }

    /**
     * Constructor: 初期値として値を引数にとります.
     *
     * @param strValue
     */
    public Formatter(String strValue) {
        this.setValue(strValue);
    }

    /**
     * Property.
     */
    private String value;

    /**
     * Accessor: valueを取得します.
     *
     * @return String
     */
    public String getValue() {
        return (this.value != null) ? this.value : "";
    }

    /**
     * Accessor: valueをセットします.
     *
     * @param strValue
     */
    public void setValue(String strValue) {
        this.value = strValue;
    }

    /* --------------------------------------------------------------------- */

    /**
     * 電話番号として正しいフォーマットか確認します.<br>
     * 「-」(ハイフン)付きのフォーマットである必要があります.
     *
     * @return boolean
     */
    public boolean validatePhoneNumber() {
        // -> Local variable.
        String strPattern = "(?!^(090|080|070))(?=^\\d{2,5}?-\\d{1,4}?-\\d{4}$)[\\d-]{12}|" +
            "(?=^(090|080|070)-\\d{4}-\\d{4}$)[\\d-]{13}|" +
            "(?=^0120-\\d{2,3}-\\d{3,4})[\\d-]{12}|" +
            "^0800-\\d{3}-\\d{4}";

        //-> Check and return value.
        return this.checkMatch(this.getValue(), strPattern);
    }

    /**
     * 電話番号として正しいフォーマットか確認します.<br>
     * 「-」(ハイフン)無しのフォーマットである必要があります.
     *
     * @return boolean
     */
    public boolean validatePhoneNumberWithOutSeparator() {
        // -> Local variable.
        String strPattern = "(?!^(090|080|070))^[\\d]{10}|" +
            "^(090|080|070)[\\d]{8}";

        //-> Check and return value.
        return this.checkMatch(this.getValue(), strPattern);
    }

    /* --------------------------------------------------------------------- */

    /**
     * 正規表現でマッチするか確認します.
     *
     * @param strTarget
     * @param strPattern
     * @return boolean
     */
    protected boolean checkMatch(String strTarget, String strPattern) {
        // -> Local variable.
        java.util.regex.Pattern objPattern;
        java.util.regex.Matcher objMatcher;

        // -> 引数チェック.
        if ((strTarget == null) || (strPattern == null))
            return false;

        // -> Pattern/Matcherオブジェクト生成.
        objPattern = Pattern.compile(strPattern);
        objMatcher = objPattern.matcher(strTarget);

        // -> Set return value.
        return objMatcher.matches();
     }
}
 ※Java勉強中なのでコードはJava.

 "(?!^(090|080|070))(?=^\\d{2,5}?-\\d{1,4}?-\\d{4}$)[\\d-]{12}|" +

 これで固定電話番号確保(2007-10-20修正. 下部「追記 - 2」参照).
 先頭3桁が「090」「080(0800含む)」「070」以外であり且つ、市外局番は2〜5桁、市内局番は1桁(田舎の方. 北海道では普通)〜4桁(東京とか)、下4桁は固定で、ハイフン含めて合計12桁である場合、または

 "(?=^(090|080|070)-\\d{4}-\\d{4}$)[\\d-]{13}|"

 携帯の古い090と新しい080およびPHSの070から始まる電話番号の場合は、3-4-4桁フォーマットでハイフン含めて合計13桁の場合、または

 "(?=^0120-\\d{2,3}-\\d{3,4})[\\d-]{12}|^0800-\\d{3}-\\d{4}";

 フリーダイヤル「0120」から始まる電話番号の場合は、4-3-3桁および4-2-4桁フォーマットでハイフン含めて合計12桁、フリーダイヤル「0800」から始まる電話番号の場合は、4-3-4桁でハイフン含めて合計13桁(2007-10-20追記. 初回修整時に桁数ミスってました).
 これらに該当するものを電話番号として正しいものとする.

 …あれ?どこか固定で13桁になった所ってありましたっけ?
 何かニュースかWEBで見た記憶が…取り敢えず気にせずいきますw
 // TODO 後で調べる.
 ※追記 - 1参照.

 まぁ、これも正規表現かじった人に言わせれば「なんじゃそりゃw」なのかもしれませんw

 …と言うか正規表現自体が未だに良く分かりません orz

 何であんなにややっこしいんだろ.
 正規表現に触れる度に、もっと自然語(普通の言語. 要するに普段使っている言葉)と親和性の高い方法って無いの?と言いたくなります.
 アレですかね?
 頭のいい人には、正規表現も自然語と同レベルに見えるんでしょうかね?

/**
 * 2007-10-17 追記 - 1(追記の割りに長文です).
 * どうやら増えたのでは無く、今まで9桁だった固定電話番号が10桁に統合された
 * ニュースを見たのを記憶していた様です.
 * http://www.wdic.org/w/WDIC/9%E6%A1%81%E3%81%AE%E9%9B%BB%E8%A9%B1%E7%95%AA%E5%8F%B7
 * 正直今年まで9桁の電話番号があるなんて知りませんでした.
 * …正規表現で一致が抜け落ちるとか、人の正規表現についてアーダコーダ言っ
 * てる場合じゃなかったと言うオチですね orz
 * まぁ、それ以前に「0120」のケースを考えてなかった事にも気づいて、抜け落
 * ち過ぎじゃねーかよっ!と.
 * 「0120」(フリーダイヤル)の場合って、ハイフンの入れる位置が「極企業側
 * の事情」によって変わりますので、4-2-4と4-3-3を想定しないといけません.
 * と言う事で、週末0120について更に追記予定.
 * ん?ハイフン無しのケース?(と言う事を知人に言われましたw)
 * 正直それは「仕様を見直した方がいい」と言いたいのが本音です.
 * それって姓と名を区切り無しに管理しているのと同じです.
 * 印刷する時、市外局番・市内局番・下四桁を区切らず(区別せず)に数値だけ
 * で印刷するんですか?と.
 * 明確に区分されているものを「無かった事に」するんですか?と.
 * そう言う事です…とは言え、「前のシステムからデータ引き継ぐ段階で既にハ
 * イフン無かったんだから仕方ねーだろ!」とか言うケースも有り得ると言えば
 * 有り得なくも無いので、それも週末に.
 * って、別に改めて書く程の事でも無いんですけど.
 * 一応動く事を確認しないと気が済まないので、改めて出直します.
 */

/**
 * 2007-10-20 追記 - 2.
 * フリーダイヤル「0120」および「0800」を追加してみました.
 * ついでに固定電話番号判定部分で括弧が1つ多かったので除去 orz
 * 更に、固定電話番号12桁(ハイフン含む)の場合、先頭に「090」「080」
 * 「070」が先頭に来た場合は除外する記述「(?!〜)」を追加してみました.
 * …何か、やればやるほど抜けが見付かるダメっぷり orz
 */

0 件のコメント: