[ Excel_Tipe29 へ戻る ]     ( Coloring  by  SyntaxHighlighter )

Tips29: JavaScript で電話番号(局番)の検証/編集    [ ソースファイル ダウンロード ]  [ JAVA 用 テストツール ]

  [ JavaScript with JSON  ( AreaCode4JSON.json ) ]   [ JavaScript ]   [ JAVA ]   [ PHP ]   [ Perl ]   [ Python ]   [ Ruby ]   [ VBA / VB6 ]   [ VB.net ]


  ( Source Code : JAVA   Ver 1.00 )    動作確認環境 [ Eclipse / JAVA 8u192 ]


//-【 JAVA 移植版 TelephoneCheck.java (Ver 1.00 , 翻訳テーブル:2022/7/1 版)  】---------------------------
//
//  電話番号のハイフン検証/編集関数
//  ( ValidateTelephone / FormatTelephone / GetTypeTelephone / PhoneNumber )
//
// 【 移植元ソース:番号翻訳テーブル 内包版 TelephoneCheck.js 】
//
//   Tips29: JavaScriptで電話番号(局番)のハイフン検証/編集
//   http://addinbox.sakura.ne.jp/Excel_Tips29.htm
//
//   Author : AddinBox(角田) http://addinbox.sakura.ne.jp/
//
//   β 1.00  , 2019/ 2/14 (JavaScript版 初版)
//   β 4.40  , 2019/ 3/27 (JavaScript版)
//   β 4.40  , 2019/ 3/27 (JAVA 移植版)
//   - - - - - - - - - - - -
//   Ver 1.00 , 2019/ 4/ 4 (JAVA 移植版, 番号翻訳テーブル:2019/4/1 版)
//   Ver 1.00 , 2019/ 5/11 (JAVA 移植版, 番号翻訳テーブル:2019/5/7 版)
//   Ver 1.00 , 2020/ 7/20 (JAVA 移植版, 番号翻訳テーブル:2020/6/1 版)
//   Ver 1.00 , 2022/ 8/ 2 (JAVA 移植版, 番号翻訳テーブル:2022/7/1 版)
//
//   *1 固定電話番号は番号翻訳テーブルによって、全国の市外局番を忠実に判定します。
//      下記で翻訳テーブルの仕組みを確認できます。
//          [ 電話番号翻訳テーブル 翻訳シュミレーター ]
//            http://addinbox.sakura.ne.jp/Excel_Tips29.htm#S2_2
//-------------------------------------------------------------------------------
//   【 サポートしている電話番号 】
//       固定電話       10桁(先頭 0) [ 0ABCDE-FGHJ ]
//       携帯電話       11桁(先頭 070/080/090) [ 0x0-CDEF-GHJK , C:1-9 ] 補:060は実施未定
//       着信課金       10桁(先頭 0120) [ 0120-DEF-GHJ ]
//       着信課金       11桁(先頭 0800) [ 0800-DEF-GHJK ]
//       IP電話       11桁(先頭 050)  [ 050-CDEF-GHJK , C:1-9 ]
//       M2M         11桁(先頭 020x) [ 020-CDE-FGHJK , C:1-3,5-9 ]
//       ポケベル       11桁(先頭 0204) [ 020-4DE-FGHJK ]
//       FMC         11桁(先頭 0600) [ 0600-DEF-GHJK ]
//       情報料代理徴収 10桁(先頭 0990) [ 0990-DEF-GHJ ] ( 災害募金サービス )
//       全国統一番号   10桁(先頭 0570) [ 0570-DEF-GHJ ] ( NTT ナビダイヤル 等 )
//-------------------------------------------------------------------------------

import java.util.regex.Pattern;


public class TelephoneCheck {


    public TelephoneCheck() {
    }

    // 番号翻訳テーブル(2022/7/1 版)
    //   固定電話の全国の局番(市外局番+市内局番)および携帯電話(070/080/090)等の局番を
    //   収録しているJSONファイル(AreaCode4JSON.json)を必要最小限の内容に編集しています。
    //   完全版のフォーマットは [ http://addinbox.sakura.ne.jp/Excel_Tips29.htm ] を参照の事。
    //   尚、このJAVA用データはJSONファイル作成ツールで一緒に作成していますので、
    //  「配列データ」の同一性/正確性は保障します。
    //
    private static final int AreaCodeArray[][] = {
        {0,1,22,41,42,54,69,70,81,114},          {0,-3,2,4,7,10,15,19,20,21},                      {-103,0,0,-4,-4,-4,3,0,0,0},
        {0,0,-4,-4,-4,-4,-4,-5,0,0},             {0,0,0,-4,-4,-4,-4,5,-4,6},                       {0,0,-5,0,-5,-4,-4,-5,-4,0},
        {0,0,-5,-4,-4,-4,-4,-5,-5,0},            {0,0,-4,-4,-4,8,9,0,0,0},                         {0,0,-4,-4,-4,0,-5,-5,0,0},
        {0,0,-4,-4,-4,-4,-5,0,0,0},              {0,0,-4,-4,11,12,13,-4,14,0},                     {0,0,-4,-4,-4,-4,-4,-5,-3,-4},
        {0,-3,-4,-4,-4,-4,-4,-3,-5,-4},          {0,0,-4,-4,-5,0,-4,-4,0,0},                       {0,0,-4,-4,-4,-4,-5,-5,-4,0},
        {0,0,-4,16,17,18,-4,-4,0,0},             {0,0,-5,0,-5,-5,-4,0,-4,-4},                      {0,0,-4,-4,-4,-4,-4,0,-5,0},
        {0,0,-4,-4,-5,-5,-5,0,-5,0},             {0,0,-4,-4,-4,-4,-4,-3,-4,-4},                    {0,0,-4,-4,-4,-4,-4,-4,-3,0},
        {0,-4,-4,-4,-4,-4,-3,-4,-4,-3},          {130,0,23,25,26,27,32,34,36,39},                  {-4,0,-3,24,-4,-4,-4,-3,-4,-4},
        {-3,0,-4,-4,-3,-3,-3,-3,-3,-3},          {0,0,0,-4,-4,-4,-3,-4,-4,0},                      {-4,-4,-4,-4,-4,-3,-4,-4,-4,-3},
        {-4,0,-3,-3,-4,28,29,30,31,-4},          {-3,-3,-3,-3,-3,-3,-3,-4,-4,-3},                  {-3,0,0,-4,-4,-4,-4,-4,-4,-4},
        {-3,-3,-4,-4,-4,-3,-3,-3,-3,-3},         {-3,0,-4,-4,-4,-4,-4,-4,-4,-4},                   {-4,-4,-3,-4,33,-4,-4,-4,-4,-4},
        {-3,0,-4,-4,-4,-4,-3,-3,-3,0},           {-4,0,-3,-3,-4,0,-4,-4,35,-4},                    {0,0,-4,-4,0,-4,-4,-4,-3,-3},
        {-4,0,-4,37,-4,-4,-3,-4,-4,38},          {-3,0,-4,-3,-3,-4,-4,0,-4,-4},                    {-3,0,0,0,0,-3,-4,-4,-4,-4},
        {0,-4,-3,40,-4,-4,-4,-4,-3,-4},          {-3,0,-4,-4,-4,-3,-3,0,-3,0},                     {0,0,0,-2,-2,-2,-2,0,0,0},
        {0,0,43,47,-3,-3,48,49,51,52},           {-2,0,44,-3,-3,-3,-3,-3,45,46},                   {-3,0,-4,-4,-4,-4,-4,-4,-4,-4},
        {-3,-3,-4,-4,-3,-3,-3,-4,-4,0},          {-2,-3,-2,-2,-2,-2,-2,-3,-3,-2},                  {0,0,-3,-3,-3,0,-4,0,-4,-4},
        {-4,0,-3,-4,-3,-4,-4,-4,-3,0},           {50,-2,0,-3,-3,-4,-4,-3,-4,-4},                   {-2,0,-4,-4,-4,-4,-4,-4,-4,-2},
        {-4,0,-3,0,-3,-3,-3,-3,-3,-3},           {0,0,-3,-4,-4,-4,0,0,0,53},                       {0,0,-5,0,-5,0,-5,0,-5,0},
        {131,0,-3,55,59,60,61,62,64,65},         {0,-4,-4,-4,-3,-3,-4,-4,-4,56},                   {0,0,-3,0,0,0,57,58,-3,0},
        {0,-4,-4,-4,-3,-3,-3,-3,-3,-3},          {0,0,0,-3,-4,0,0,-4,0,0},                         {0,0,-3,-3,-4,-4,-3,-4,-4,-3},
        {-4,-4,-3,-4,-4,-4,-4,-4,-4,-3},         {0,-4,-4,-4,-4,-4,-4,-4,-4,-4},                   {-110,0,-4,-4,-4,-4,63,-4,-4,0},
        {0,0,-4,-4,-4,-4,-4,-4,0,-5},            {0,-4,-3,-3,-4,-4,-4,-4,0,0},                     {0,0,-3,-3,-4,-4,-4,66,-4,68},
        {0,0,-4,-4,-4,0,0,-4,-4,67},             {0,0,-5,-5,-5,-5,-5,-4,-4,-5},                    {0,0,-4,-4,-4,-4,-4,-4,-4,-3},
        {132,0,0,0,-2,0,-2,-2,0,0},              {133,0,71,72,73,-3,75,76,-3,77},                  {0,-4,-3,-3,-3,-4,-3,-3,-3,-3},
        {0,0,0,0,-3,-4,-4,-4,-4,-4},             {-4,0,-4,-4,-4,-4,74,-4,-4,-4},                   {0,0,0,-4,-4,-4,-4,0,-5,0},
        {0,-4,-3,-4,-3,-4,-4,-4,-4,0},           {-4,-4,-4,-4,-4,-3,-4,0,-4,-4},                   {-4,-4,-3,-3,78,79,80,-4,-4,-4},
        {0,0,-3,-3,-3,-3,-4,-4,-4,-3},           {-3,0,-4,-4,-4,-3,-3,-4,-4,-3},                   {-3,0,-4,-4,-4,-4,-3,-3,-4,-4},
        {134,0,82,87,94,96,98,111,112,113},      {-4,0,-3,-4,83,-3,-4,-4,-3,84},                   {-3,0,-3,-3,-4,-4,-4,-4,-4,-3},
        {-3,0,85,-4,86,-4,-3,-4,-4,0},           {-4,-3,-3,-3,-3,-3,-3,-3,-3,-3},                  {-4,-3,-3,-3,-4,-4,0,0,0,0},
        {0,0,-3,-4,-4,-4,88,89,91,92},           {-3,0,-4,-4,-4,-4,-4,-4,-4,-4},                   {0,0,-4,-4,-4,-4,90,-3,-3,0},
        {-4,0,-4,-4,-4,-4,-3,-3,-3,-4},          {0,0,-4,-4,-4,-4,0,-5,-5,0},                      {-3,0,-3,-3,-3,-3,93,-3,-3,-3},
        {0,0,-5,-3,0,-5,-3,-5,-5,0},             {0,0,0,0,0,-4,-4,95,-4,-3},                       {0,0,-4,-4,-4,-4,-4,-5,-4,0},
        {0,97,-4,-4,-4,-4,-4,-4,-4,-4},          {0,0,-5,0,-5,0,0,0,0,0},                          {0,0,-3,99,-3,101,103,105,108,109},
        {0,0,-4,-4,-4,-4,100,-4,-4,0},           {0,0,-3,-3,-3,0,-4,0,-3,0},                       {0,0,-3,0,-4,102,-4,-4,0,0},
        {-4,0,-3,0,-4,0,0,0,-4,0},               {-3,0,-4,-4,-4,-4,-4,-4,-4,104},                  {-4,-3,-4,-4,-4,-4,-4,-3,-3,-4},
        {0,0,106,107,-4,-4,-4,-4,-4,-4},         {0,0,-3,-3,-3,-4,-3,-4,-3,0},                     {0,0,0,-4,-4,-4,-4,-3,-3,0},
        {-3,0,-4,-4,-4,-4,-4,-4,-4,-3},          {-3,0,-4,-4,-3,-3,-4,-4,-4,110},                  {0,0,-4,-4,0,-3,0,-3,0,-3},
        {0,0,0,0,0,-4,0,-4,-3,-4},               {-4,0,0,-4,-4,-4,-3,-4,-3,-4},                    {0,0,-4,-4,-4,-4,-4,-4,-4,-3},
        {135,0,115,116,117,118,119,120,121,123}, {-4,0,-3,-3,-3,-3,-3,-3,-3,-3},                   {-4,0,-3,-3,-3,-3,-3,-3,-3,-3},
        {-4,0,-4,-4,-4,0,-4,-4,-4,-4},           {-4,0,-4,0,-4,-4,-4,-4,-3,-4},                    {0,0,-3,-3,-4,-4,-4,-4,-4,-4},
        {0,0,-4,-4,-4,-3,0,-4,-4,-4},            {122,0,-4,-4,-4,-4,-4,-4,-3,-3},                  {0,0,-5,-4,-4,-4,-4,-4,-4,-4},
        {-109,124,-3,125,128,-4,129,-4,-3,0},    {0,0,-5,-5,0,0,0,0,0,0},                          {0,0,-4,126,127,-4,-4,-4,-4,0},
        {0,-3,-4,-4,-4,-4,-4,-4,-4,-4},          {-4,-4,0,-3,0,-3,0,-3,0,-4},                      {-3,0,-4,-4,-4,-4,-4,-3,-3,-4},
        {0,0,-4,-4,-4,-4,-4,-4,-4,-5},           {0,-106,-106,-106,-107,-106,-106,-106,-106,-106}, {0,-105,-105,-105,-105,-105,-105,-105,-105,-105},
        {-108,0,0,0,0,0,0,0,0,0},                {0,-102,-102,-102,-102,-102,-102,-102,-102,-102}, {-104,-102,-102,-102,-102,-102,-102,-102,-102,-102},
        {0,-102,-102,-102,-102,-102,-102,-102,-102,-102}
    };


    //-------------------------------------------------------------------------------
    // JavaScript版では返却値用の連想配列を初期化する InitTelephone 関数を用意しているが、
    // JAVA版では返却値のスタイルをクラスオブジェクトにしている。
    // 初期化はコンストラクタにて実施しているので、初期化関数 ( InitTelephone )は設けない。
    //-------------------------------------------------------------------------------

    // 返却値のクラス定義( ValidateTelephone , FormatTelephone )
    public static class TelephoneCheckValue {
        public int    TelType;
        public int    EditType;
        public String TelEdit;
        public int    ErrId;

        public TelephoneCheckValue() {
            this.TelType = -1;
            this.EditType = 9;
            this.TelEdit = "";
            this.ErrId = 0;
        }
    }

    // 返却値のクラス定義( GetTypeTelephone )
    public static class TelephoneType {
        public int    TelType;
        public int    SizeAll;
        public int    Size1;
        public int    Size2;
        public int    Size3;
        public int    ErrId;

        public TelephoneType() {
            this.TelType = -1;
            this.SizeAll = 0;
            this.Size1 = 0;
            this.Size2 = 0;
            this.Size3 = 0;
            this.ErrId = 0;
        }
    }


    //-------------------------------------------------------------------------------
    // 電話番号のフォーマット&検証 ( PhoneNumber )
    //    --- ValidateTelephone/FormatTelephone の簡易インターフェース ---
    //
    // TelCode -- 半角文字列[ 0-9, -, (, ) ]
    //            固定電話/携帯電話などの[ハイフン/括弧]編集 or 未編集電話番号
    //
    // Action  -- "V"        : 電話番号の検証
    //            "F1"〜"F6" : 電話番号の区切り編集( 2桁目が EditType の値 )
    //
    // 返却値
    //    Action= "V"        -- "0": 検証エラー , "1":検証OK , "2":検証OK(電話番号が数字のみ)
    //                          ( JAVA 版では 文字列の "0"/"1"/"2" が返ります)
    //
    //          = "F1"〜"F6" -- 電話番号が正しい場合: EditType(2桁目)に従って編集した電話番号
    //                          電話番号が誤っている場合: "Phone Error"
    //
    //          上記以外     -- "" で返ります。
    // 
    //-------------------------------------------------------------------------------
    public static String PhoneNumber(String TelCode, String Action)
    {

        // FormatTelephone/ValidateTelephone の返却値
        TelephoneCheckValue Result = new TelephoneCheckValue();

        Pattern patternAction = Pattern.compile("^(([Ff][1-6])|[Vv])$");  // "F1"〜"F6" or "V"

        if (patternAction.matcher(Action).matches() != true) {
            return "";
        }

        if ( (Action.toUpperCase()).equals("V") ) {
            Result = ValidateTelephone(TelCode);
            switch (Result.ErrId) {
                case 0:
                    return "1";  // OK
                case 8:
                    return "2";  // OK (電話番号が数字のみ)
                default:
                    return "0";  // エラー
            }
        } else {
            Result = FormatTelephone(TelCode, Integer.parseInt(Action.substring(1)) );
            if (Result.ErrId == 0) {
                return Result.TelEdit;
            } else {
                return "Phone Error";
            }
        }
    }


    //-------------------------------------------------------------------------------
    // 電話番号の検証 ( ValidateTelephone )
    //
    // TelCode -- 半角文字列[ 0-9, -, (, ) ]
    //            固定電話/携帯電話などの[ハイフン/括弧]編集
    //
    // 返却値  -- class TelephoneCheckValue (TelType, EditType, TelEdit, ErrId )
    //   TelType   1:固定電話(10桁), 2:携帯電話(070/080/090,11桁), 3:着信課金(0120,10桁),
    //             4:着信課金(0800,11桁), 5:IP電話(050,11桁), 6:M2M(020x,11桁,x≠4),
    //             7:ポケベル(0204,11桁), 8:FMC(0600,11桁), 9:情報料徴収(0990,10桁),
    //             10:統一番号(0570,10桁), -1:other
    //
    //   EditType  1: 0AB-CDE-FGHJ, 2: 0AB(CDE)FGHJ, 3: (0AB)CDE-FGHJ, 9:other
    //             携帯電話のみ、[3-4-4 桁]で区切る⇒1〜3 , [3-3-5 桁]で区切る⇒4〜6
    //
    //   TelEdit   TelType/EditType で編集し直された電話番号(正しい編集結果)
    //               ErrId=0/1/3/5 : 同じパターンで編集し直された電話番号
    //                 〃 =8       : ハイフン編集した電話番号
    //                 〃 =2       : TelCode のまま(未使用局番なので正誤は判断しない)
    //                 〃 =4/6/9   : 空文字
    //
    //   ErrId     0:OK, 1:区切り位置不正, 2:未使用局番(固定電話), 3:市内局番1桁目が[0 or 1](固定電話),
    //             4:引数不正([数字,ハイフン,括弧]以外がある or 編集パターン不正 or '0'始まりでない or 桁数不足),
    //             5:引数不正(局番タイプに応じた桁数と不一致),
    //             6:その他のエラー, 8:OK(数字のみ指定), 9:引数未定義(TelCode)
    //-------------------------------------------------------------------------------
    public static TelephoneCheckValue ValidateTelephone(String TelCode)
    {
        // 返却値
        TelephoneCheckValue Result = new TelephoneCheckValue();
 
        // FormatTelephoneの返却値
        TelephoneCheckValue ResultFormat = new TelephoneCheckValue();
        // 携帯電話(3-3-5桁区切り編集の再取得用)
        TelephoneCheckValue ResultFormat2 = new TelephoneCheckValue();
 
        String TelNumber;    // ハイフン,括弧除去(数字のみ)
        int EditType;
 
 
        // 厳密なチェックは FormatTelephone の結果と比較して行なうので
        // 下記のパターンチェックでは桁数については曖昧で構わない('0'始まりのみチェックする)
        Pattern pattern0 = Pattern.compile("^0[0-9]+$");             // 0123456789
        Pattern pattern1 = Pattern.compile("^0[0-9]+-[0-9]+-[0-9]+$");     // 012-345-6789
        Pattern pattern2 = Pattern.compile("^0[0-9]+\\([0-9]+\\)[0-9]+$");   // 012(345)6789
        Pattern pattern3 = Pattern.compile("^\\(0[0-9]+\\)[0-9]+-[0-9]+$");  // (012)345-6789
 
 
        if (pattern0.matcher(TelCode).matches() == true) {  // (数字のみ)  0123456789
            // 数字のみ指定 ⇒ 編集のみ行って比較検証は無し
            ResultFormat = FormatTelephone(TelCode, 1);  // ハイフン編集で固定
            Result.TelType = ResultFormat.TelType;
            Result.EditType = 1;
            Result.TelEdit = ResultFormat.TelEdit;
            // ValidateTephone用エラーコードに差替え
            switch (ResultFormat.ErrId) {
                case 0:
                    Result.ErrId = 8;  // OK(数字のみ指定)
                    break;
                case 1:
                    Result.ErrId = 2;  // 未使用局番(固定電話番号)
                    break;
                case 2:
                    Result.ErrId = 3;  // 市内局番1桁目が[0 or 1](固定電話)
                    break;
                case 3:
                    Result.ErrId = 4;  // 桁数不足(数字が10桁未満)
                    break;
                case 4:
                    Result.ErrId = 5;  // 局番タイプに応じた桁数と不一致
                    break;
                default:
                    Result.ErrId = 6;  // その他のエラー
            }
            return Result;
        } else if (pattern1.matcher(TelCode).matches() == true) {  // EditType:1  012-345-6789
            EditType = 1;
            Result.EditType = 1;
        } else if (pattern2.matcher(TelCode).matches() == true) {  // EditType:2 012(345)6789
            EditType = 2;
            Result.EditType = 2;
        } else if (pattern3.matcher(TelCode).matches() == true) {  // EditType:3 (012)345-6789
            EditType = 3;
            Result.EditType = 3;
        } else {
            // [数字,ハイフン,括弧]以外がある or 編集パターン不正 or '0'始まりでない
            Result.ErrId = 4;
            Result.TelEdit = TelCode;
            return Result;
        }
 
        // FormatTelephone 用に[ハイフン,括弧]を除去して「数字のみ」にする
        TelNumber = TelCode.replaceAll("-|\\(|\\)","");
 
        ResultFormat = FormatTelephone(TelNumber, EditType);
        // FormatTelephone で編集し直した結果と比較して検証する
        // ErrId で返るのは
        //    0:OK, 1:未使用局番(固定電話), 2:市内局番1桁目が[0 or 1](固定電話)
        //    3:引数不正(TelCode: 数字が10桁未満),
        //    4:引数不正(TelCode: 局番タイプの桁数と不一致)
        // 下記状態は既にチェック済なので、その値が返ることは無い
        //    3:引数不正(TelCode: ['0'始まりの数字]以外)
        //    6:引数不正(EditType)
        //    9:引数未定義(TelCode/EditType)
 
        Result.TelType = ResultFormat.TelType;
        Result.TelEdit = ResultFormat.TelEdit;
        // ValidateTephone用エラーコードに差替え
        switch (ResultFormat.ErrId) {
            case 0:  // FormatTelephoneでOK ⇒ 正しい電話番号
                if (TelCode.equals(ResultFormat.TelEdit)) {
                    Result.ErrId = 0;  // OK (区切り位置も正しい)
                } else {
                    if (ResultFormat.TelType == 2) { // 携帯電話(070/080/090)
                        // 携帯電話の場合、別の区切り方[3-3-5 桁]で再チェック
                        ResultFormat2 = FormatTelephone(TelNumber, EditType + 3);
                        if (TelCode.equals(ResultFormat2.TelEdit)) {
                            // OK (3-3-5桁で一致)
                            Result.ErrId = 0;
                            Result.TelEdit = ResultFormat2.TelEdit;
                            Result.EditType = EditType + 3;
                        } else {
                            Result.ErrId = 1;  // 区切り位置不正
                        }
                    } else {
                        // 携帯電話 以外
                        Result.ErrId = 1;  // 区切り位置不正
                    }
                }
                break;
            case 1:
                Result.ErrId = 2;  // 未使用局番(固定電話番号)
                Result.TelEdit = TelCode;  // ResultFormat.TelEdit(=TelNumber)なので入力値に差し替える
                break;
            case 2:
                Result.ErrId = 3;  // 市内局番1桁目が[0 or 1](固定電話)
                break;
            case 3:
                Result.ErrId = 4;  // 桁数不足(数字が10桁未満)
                break;
            case 4:
                Result.ErrId = 5;  // 局番タイプに応じた桁数と不一致
                break;
            default:
                Result.ErrId = 6;  // その他のエラー
        }
        return Result;
    }
 
 
    //-------------------------------------------------------------------------------
    // 電話番号のハイフン編集 ( FormatTelephone )
    //
    // TelCode  -- 半角数字文字列[ 0-9 ], 10 or 11桁(先頭'0'固定)
    //             固定電話/携帯電話などの電話番号
    //
    // EditType -- 数値
    //             1or4: 0AB-CDE-FGHJ , 2or5: 0AB(CDE)FGHJ , 3or6: (0AB)CDE-FGHJ
    //             携帯電話のみ、[3-4-4 桁]で区切る⇒1〜3 , [3-3-5 桁]で区切る⇒4〜6
    //
    // 返却値 -- class TelephoneCheckValue (TelType, EditType, TelEdit, ErrId )
    //   TelType   1:固定電話(10桁), 2:携帯電話(070/080/090,11桁), 3:着信課金(0120,10桁),
    //             4:着信課金(0800,11桁), 5:IP電話(050,11桁), 6:M2M(020x,11桁,x≠4),
    //             7:ポケベル(0204,11桁), 8:FMC(0600,11桁), 9:情報料徴収(0990,10桁),
    //             10:統一番号(0570,10桁), -1:other
    //
    //   EditType  1or4: 0AB-CDE-FGHJ, 2or5: 0AB(CDE)FGHJ, 3or6: (0AB)CDE-FGHJ, 9:other
    //
    //   TelEdit   編集された電話番号
    //               ErrId=0/2/4 : 編集された電話番号
    //                〃  =1     : TelCode の内容のまま
    //                〃  =3/6/9 : 空文字
    //
    //   ErrId     0:OK, 1:未使用局番(固定電話), 2:市内局番1桁目が[0 or 1](固定電話),
    //             3:引数不正(TelCode: ['0'始まりの数字]以外 or 10桁未満),
    //             4:引数不正(TelCode: 局番タイプに応じた桁数と不一致)
    //             6:引数不正(EditType), 9:引数未定義(TelCode/EditType)
    //-------------------------------------------------------------------------------
    public static TelephoneCheckValue FormatTelephone(String TelCode, int EditType)
    {
        // 返却値
        TelephoneCheckValue Result = new TelephoneCheckValue();
 
        // GetTypeTelephone 返却値
        TelephoneType ResultType = new TelephoneType();
 
        Pattern TelPattern  = Pattern.compile("^0[0-9]{9,}$");   // '0'始まりの数字文字列(10桁以上)
 
        // ['0'始まりの数字文字列(10桁以上)]のチェック
        // (番号翻訳(GetTypeTelephone)後に完全な桁数チェックを行なう。ここでは10桁未満のみNG)
        if (TelPattern.matcher(TelCode).matches() == false) {
            Result.ErrId = 3;
            return Result;
        }
 
        // EditTypeのチェック
        if (EditType >= 1 && EditType <= 6) {
            Result.EditType = EditType;    // OK
        } else {
            Result.ErrId = 6;
            return Result;
        }
 
        ResultType = GetTypeTelephone(TelCode);  // 番号翻訳して電話番号の種別と桁区切り情報を取得する
        // ErrId で返るのは
        //    0:OK, 1:未使用局番(固定電話), 2:市内局番1桁目が[0 or 1](固定電話)
        // 下記状態は既にチェック済なので、その値が返ることは無い
        //    3:電話番号種別が不明(桁数不足で番号翻訳未了)← 10桁以上なので未了は無い
        //    8:引数不正(TelCode: ['0'始まりの数字]以外)
        //    9:引数未定義(TelCode)
 
        Result.TelType = ResultType.TelType;
        Result.ErrId = ResultType.ErrId;
        if (ResultType.ErrId == 1) {
            // 未使用局番(固定電話)
            Result.TelEdit = TelCode;
        } else {
            // 0:OK  or  2:市内局番1桁目が[0 or 1](固定電話)
            if (ResultType.TelType == 2 && EditType >= 4) {
                // 携帯電話(070/080/090)で[3-3-5 桁区切り, 0x0-CDE-FGHJK]を指定された場合
                Result.TelEdit = InsertSeparator(TelCode, EditType, 3, 3);
            } else {
                // 携帯電話(3-4-4桁区切り)を含め、他は返却値で区切りパターンが得られる
                // 固定電話では[市外局番桁数/市内局番桁数/加入者番号桁数(4)]が得られる
                if (ResultType.Size2 == 0) {
                    // 固定電話で、市内局番なし [ 0ABCDE-FGHJ ] (現在、この地域は存在しない)
                    Result.TelEdit  = TelCode.substring(0, 6) + "-" + TelCode.substring(6);
                } else {
                    Result.TelEdit = InsertSeparator(TelCode, EditType, ResultType.Size1, ResultType.Size2);
                }
            }
 
            if (TelCode.length() != ResultType.SizeAll) {
                Result.ErrId = 4;  // 桁数エラー(局番タイプに応じた桁数と不一致)
            }
        }
 
        return Result;
    }
 
 
    private static String InsertSeparator(String TelCode, int EditType, int Size1, int Size2)
    {
        String Result = "";
        String EditCode1 = TelCode.substring(0, Size1);              // 1st section :固定電話では市外局番(先頭'0')
        String EditCode2 = TelCode.substring(Size1, Size1 + Size2);  // 2nd section :固定電話では市内局番
        String EditCode3 = TelCode.substring(Size1 + Size2);         // 3rd section :固定電話では加入者番号(末尾まで取り出す)
 
        switch (EditType) {
            case 1:  // 0AB-CDE-FGHJ
            case 4:
                Result = EditCode1 + "-" + EditCode2 + "-" + EditCode3;
                break;
            case 2:  // 0AB(CDE)FGHJ
            case 5:
                Result = EditCode1 + "(" + EditCode2 + ")" + EditCode3;
                break;
            case 3:  // (0AB)CDE-FGHJ
            case 6:
                Result = "(" + EditCode1 + ")" + EditCode2 + "-" + EditCode3;
        }
        return Result;
    }



    //-------------------------------------------------------------------------------
    // 電話番号タイプの取得 ( GetTypeTelephone )
    //
    // TelCode  -- 半角数字文字列(2桁以上, 先頭'0'固定)
    //             固定電話/携帯電話などの電話番号(途中までの内容でも可)
    //
    // 返却値 -- class TelephoneType (TelType, SizeAll, Size1, Size2, Size3, ErrId)
    //   TelType   1:固定電話(10桁), 2:携帯電話(070/080/090,11桁), 3:着信課金(0120,10桁),
    //             4:着信課金(0800,11桁), 5:IP電話(050,11桁), 6:M2M(020x,11桁,x≠4),
    //             7:ポケベル(0204,11桁), 8:FMC(0600,11桁), 9:情報料徴収(0990,10桁),
    //             10:統一番号(0570,10桁), -1:other
    //
    //   SizeAll   ErrId=0/2 : TelType に応じた電話番号の桁数(10 or 11, Size1〜3の合計値)
    //             ErrId=1/3/8/9 : 0
    //
    //   Size1-3   ErrId=0/2 : TelType に応じた電話番号の区切り桁数(Size1 には先頭'0'含む)
    //             ErrId=1/3/8/9 : 0
    //             (携帯電話(TelType=2)は[3-4-4 桁区切り]のみで返す)
    //
    //   ErrId     0:OK, 1:未使用局番(固定電話), 2:市内局番1桁目が[0 or 1](固定電話),
    //             3:電話番号種別が不明(桁数不足で番号翻訳未了)
    //             8:引数不正(TelCode: ['0'始まりの数字]以外), 9:引数未定義(TelCode)
    //-------------------------------------------------------------------------------
    public static TelephoneType GetTypeTelephone(String TelCode)
    {
        // 返却値
        TelephoneType Result = new TelephoneType();
 
        int AreaCodeLength = 0;
        int CityCodeLength = 0;
        String CityCode1 = "";  // 市内局番の1桁目
        int idx = 0;
        int cnt = 0;
        int num = 0;
        int LinkValue = 0;
        int TelType = 0;
 
        Pattern TelPattern  = Pattern.compile("^0[0-9]+$");   // '0'始まりの数字文字列(桁数制限なし)
 
        // ( 1)固定電話       10桁 [ 桁区切りは番号翻訳結果に拠る ]
        // ( 2)携帯電話       11桁 [ 0x0-CDEF-GHJK , 070/080/090 ]
        // ( 3)着信課金       10桁 [ 0120-DEF-GHJ  ]
        // ( 4)着信課金       11桁 [ 0800-DEF-GHJK ]
        // ( 5)IP電話       11桁 [ 050-CDEF-GHJK ]
        // ( 6)M2M         11桁 [ 020-CDE-FGHJK ]
        // ( 7)ポケベル       11桁 [ 020-4DE-FGHJK ]
        // ( 8)FMC         11桁 [ 0600-DEF-GHJK ]
        // ( 9)情報料代理徴収 10桁 [ 0990-DEF-GHJ  ]
        // (10)全国統一番号   10桁 [ 0570-DEF-GHJ  ]
        //  SizeInfo [SizeAll, Size1, Size2, Size3]
        int SizeInfo[][] = {
               {0,0,0,0},  {10,0,0,0}, {11,3,4,4}, {10,4,3,3}, {11,4,3,4},
               {11,3,4,4}, {11,3,3,5}, {11,3,3,5}, {11,4,3,4}, {10,4,3,3}, {10,4,3,3}
            };
 
        // ['0'始まりの数字文字列(桁数制限なし)]のチェック
        if (TelPattern.matcher(TelCode).matches() == false) {
            Result.ErrId = 8;
            return Result;
        }
 
        // ※ 番号翻訳テーブルをソースコード内に直に収録しているので
        //    JSONファイルの読み込み処理は必要ない。
 
        // 番号翻訳テーブルから局番情報(市外局番の桁数 or [携帯番号 等]のTelType情報)を取得する。
        // [TelCode]の長さが[局番桁数 未満]も受け入れているので『番号翻訳 途中』でのループ終了(TelType= -1)もある。
        idx = 0;
        TelType = -1;
        AreaCodeLength = 0;
        for (cnt = 1; (cnt <= 5) && (cnt < TelCode.length()); cnt++) {  // 番号翻訳テーブルはA〜Eコードの5段
            num = Integer.parseInt(TelCode.substring(cnt, cnt + 1));    // 電話番号の2桁目以降(1桁目は'0')を順次取り出す
            LinkValue = AreaCodeArray[idx][num];
            if (LinkValue == 0) {   // 番号翻訳 終了(固定電話 未使用局番)
                TelType = 1;
                AreaCodeLength = 0;
                break;
            } else if (LinkValue < 0) {  // 番号翻訳 終了
                if (LinkValue > -100) {
                    // 固定電話の市外局番桁数(符号反転値) 実際の収録値[ -2 〜 -5 ]
                    TelType = 1;
                    AreaCodeLength = LinkValue * (-1);  // 市外局番 桁数決定(先頭の "0" 含む)
                } else {
                    // 携帯電話 等のTelType値(符号反転値 - 100) 実際の収録値[ -102 〜 -110 ]
                    TelType = (LinkValue * (-1)) - 100;
                }
                break;
            } else {  // プラス値
                idx = LinkValue;  // 検索継続(収録値は NextIndex)
            }
        };
 
        // TelType に応じた桁区切りを設定する
        // 固定電話(TelType=1)では市外局番桁数(AreaCodeLength)に従って設定する
        // Size1 の値は[先頭'0'含む]
        Result.TelType = TelType;
        switch (TelType) {
            case -1:
                // 電話番号種別が不明(桁数不足で番号翻訳未了)
                Result.ErrId = 3;
                break;
            case 1:
                // 固定電話
                if (AreaCodeLength == 0) {  // 未使用 局番
                    Result.ErrId = 1;
                } else if (AreaCodeLength == 6) {  // 市内局番なし [ 0ABCDE-FGHJ ] (現在、この地域は存在しない)
                    Result.ErrId = 0;
                    Result.SizeAll = 10;
                    Result.Size1 = 6;
                    Result.Size2 = 0;
                    Result.Size3 = 4;
                } else {
                    CityCodeLength = 6 - AreaCodeLength;  // 10 - AreaCodeLength - 4(加入者番号)
                    if (TelCode.length() < (AreaCodeLength + 1)) {
                        // [TelCode]が市内局番の桁位置までないので市内局番適否の判定不可⇒ OK で返す
                        Result.ErrId = 0;
                    } else {
                        // FormatTelephone から呼ばれる場合は 10桁以上なので必ず判定可能
                        CityCode1 = TelCode.substring(AreaCodeLength, AreaCodeLength + 1);  // 市内局番 1桁目
                        if (CityCode1 == "0" || CityCode1 == "1") {
                            Result.ErrId = 2;  // 市内局番1桁目に0/1は割り当てられない
                        } else {
                            Result.ErrId = 0;  // OK
                        }
                    }
                    Result.SizeAll = 10;
                    Result.Size1 = AreaCodeLength;
                    Result.Size2 = CityCodeLength;
                    Result.Size3 = 4;
                }
                break;
            default:
                // TelType = 2〜10, SizeInfoテーブルから桁情報を設定する
                Result.ErrId = 0;  // OK
                Result.SizeAll = SizeInfo[TelType][0];
                Result.Size1   = SizeInfo[TelType][1];
                Result.Size2   = SizeInfo[TelType][2];
                Result.Size3   = SizeInfo[TelType][3];
        }
        return Result;
    }
 
}