[ Excel_Tipe29 へ戻る ]     ( Coloring  by  SyntaxHighlighter )

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

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


  ( Source Code : Perl   Ver 1.00 )    動作確認環境 [ Padre / Perl 5.14.2 ]

use utf8;
use strict;

#//--【 Perl 移植版 TelephoneCheck.pl (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 (Perl 移植)
#//   - - - - - - - - - - - -
#//   Ver 1.00 , 2019/ 4/ 4 (Perl 移植, 番号翻訳テーブル:2019/4/1 版)
#//   Ver 1.00 , 2019/ 5/11 (Perl 移植, 番号翻訳テーブル:2019/5/7 版)
#//   Ver 1.00 , 2020/ 7/20 (Perl 移植, 番号翻訳テーブル:2020/6/1 版)
#//   Ver 1.00 , 2022/ 8/ 2 (Perl 移植, 番号翻訳テーブル: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 ]
#//-------------------------------------------------------------------------------


# 番号翻訳テーブル(2022/7/1 版)
#   固定電話の全国の局番(市外局番+市内局番)および携帯電話(070/080/090)等の局番を
#   収録しているJSONファイル(AreaCode4JSON.json)を必要最小限の内容に編集しています。
#   完全版のフォーマットは [ http://addinbox.sakura.ne.jp/Excel_Tips29.htm ] を参照の事。
#   尚、このPerl用データはJSONファイル作成ツールで一緒に作成していますので、
#  「配列データ」の同一性/正確性は保障します。
 
my @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]
);


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

    my ($TelCode, $Action) = @_;

    # FormatTelephone/ValidateTelephone の返却値
    my %Result = InitTelephone("Value");

    my $strTelCode = "";
    my $strAction = "";

    my $patternAction = qr/^(([Ff][1-6])|[Vv])$/;    # "F1"〜"F6" or "V"

    if (!defined($Action)) {
        return "";
    } else {
        # 空文字を連結して強制的に文字列型にする
        if (($Action . "") =~ /$patternAction/) {
            $strAction = uc(($Action . ""));
        } else {
            return "";
        }
    }

    if (!defined($TelCode)) {
        return "";
    } else {
        # 空文字を連結して強制的に文字列型にする
        $strTelCode = $TelCode . "";
    }

    if ($strAction eq "V") {
        %Result = ValidateTelephone($strTelCode);
        if ($Result{ErrId} == 0) {
            return 1;  # OK(Boolean変換でTrue)
        } elsif ($Result{ErrId} == 8) {
            return 2;  # OK (電話番号が数字のみ, Boolean変換でTrue)
        } else {
            return 0;  # エラー(Boolean変換でFalse)
        }
    } else {
        %Result = FormatTelephone($strTelCode, (substr($strAction, 1) * 1) );
        if ($Result{ErrId} == 0) {
            return $Result{TelEdit};
        } else {
            return "Phone Error";
        }
    }
}


#//-------------------------------------------------------------------------------
#// 返却値を受け取る変数に連想配列の初期設定 ( InitTelephone )
#// 
#// Target -- "Value" or "Type" (左記以外 "Value" 扱い)
#//
#// 返却値 -- Target = "Value" の場合、下記の連想配列
#//              (TelType => -1, EditType => 9, TelEdit => "", ErrId => 0)
#//           Target = "Type" の場合、下記の連想配列
#//              (TelType => -1, SizeAll => 0, Size1 => 0, Size2 => 0, Size3 => 0, ErrId => 0)
#//-------------------------------------------------------------------------------
sub InitTelephone {
    my ($Target) = @_;

    my $Target2 = "";

    if (!defined($Target)) {
        $Target2 = "Value";
    } else {
        # 空文字を連結して強制的に文字列型にする
        if (uc($Target . "") eq "VALUE") {
            $Target2 = "Value";
        } elsif (uc($Target . "") eq "TYPE") {
            $Target2 = "Type";
        } else {
            $Target2 = "Value";
        }
    }

    if ($Target2 eq "Value") {
        return (TelType => -1, EditType => 9, TelEdit => "", ErrId => 0);
    } else {
        return (TelType => -1, SizeAll => 0, Size1 => 0, Size2 => 0, Size3 => 0, ErrId => 0);
    }
}


#//-------------------------------------------------------------------------------
#// 電話番号の検証 ( ValidateTelephone )
#//
#// TelCode -- 半角文字列[ 0-9, -, (, ) ]
#//            固定電話/携帯電話などの[ハイフン/括弧]編集
#//
#// 返却値  -- (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
#//             携帯電話のみ、[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)
#//-------------------------------------------------------------------------------
sub ValidateTelephone {
    my ($TelCode) = @_;

    # 返却値
    my %Result = InitTelephone("Value");

    # FormatTelephoneの返却値
    my %ResultFormat = InitTelephone("Value");
    # 携帯電話(3-3-5桁区切り編集の再取得用)
    my %ResultFormat2 = InitTelephone("Value");

    my $strTelCode = "";  # Perlには引数に型指定が無いので空文字を連結して強制的に文字列型にする
    my $TelNumber = "";   # ハイフン,括弧除去(数字のみ)
    my $EditType = 0;

    # 厳密なチェックは FormatTelephone の結果と比較して行なうので
    # 下記のパターンチェックでは桁数については曖昧で構わない。
    my $pattern0 = qr/^0\d+$/;            # 0123456789
    my $pattern1 = qr/^0\d+-\d+-\d+$/;    # 012-345-6789
    my $pattern2 = qr/^0\d+\(\d+\)\d+$/;  # 012(345)6789
    my $pattern3 = qr/^\(0\d+\)\d+-\d+$/; # (012)345-6789

    if (!defined($TelCode)) {
        $Result{ErrId} = 9;  # 未定義
        return %Result;
    } else {
        # 空文字を連結して強制的に文字列型にする
        $strTelCode = $TelCode . "";
    }

    if ($strTelCode =~ /$pattern0/) {  # (数字のみ)  0123456789
        # 数字のみ指定 ⇒ 編集のみ行って比較検証は無し
        %ResultFormat = FormatTelephone($strTelCode, 1);  # ハイフン編集で固定
        $Result{TelType} = $ResultFormat{TelType};
        $Result{EditType} = 1;
        $Result{TelEdit} = $ResultFormat{TelEdit};
        # ValidateTephone用エラーコードに差替え
        if ($ResultFormat{ErrId} == 0) {
            $Result{ErrId} = 8;  # OK(数字のみ指定)
        } elsif ($ResultFormat{ErrId} == 1) {
            $Result{ErrId} = 2;  # 未使用局番(固定電話番号)
        } elsif ($ResultFormat{ErrId} == 2) {
            $Result{ErrId} = 3;  # 市内局番1桁目が[0 or 1](固定電話)
        } elsif ($ResultFormat{ErrId} == 3) {
            $Result{ErrId} = 4;  # 桁数不足(数字が10桁未満)
        } elsif ($ResultFormat{ErrId} == 4) {
            $Result{ErrId} = 5;  # 局番タイプに応じた桁数と不一致
        } else {
            $Result{ErrId} = 6;  # その他のエラー
        }
        return %Result;
    } elsif ($strTelCode =~ /$pattern1/) {  # EditType:1  012-345-6789
        $EditType = 1;
        $Result{EditType} = 1;
    } elsif ($strTelCode =~ /$pattern2/) {  # EditType:2 012(345)6789
        $EditType = 2;
        $Result{EditType} = 2;
    } elsif ($strTelCode =~ /$pattern3/) {  # EditType:3 (012)345-6789
        $EditType = 3;
        $Result{EditType} = 3;
    } else {
        # [数字,ハイフン,括弧]以外がある or 編集パターン不正 or '0'始まりでない
        $Result{ErrId} = 4;
        $Result{TelEdit} = $strTelCode;
        return %Result;
    }

    # FormatTelephone 用に[ハイフン,括弧]を除去して「数字のみ」にする
    $TelNumber = $strTelCode;
    $TelNumber =~ s/-|\(|\)//g;

    %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用エラーコードに差替え
    if ($ResultFormat{ErrId} == 0) {  # FormatTelephoneでOK ⇒ 正しい電話番号
        if ($strTelCode eq $ResultFormat{TelEdit}) {
            $Result{ErrId} = 0;  # OK (区切り位置も正しい)
        } else {
            if ($ResultFormat{TelType} == 2) { # 携帯電話(070/080/090)
                # 携帯電話の場合、別の区切り方[3-3-5 桁]で再チェック
                %ResultFormat2 = FormatTelephone($TelNumber, $EditType + 3);
                if ($strTelCode eq $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;  # 区切り位置不正
            }
        }
    } elsif ($ResultFormat{ErrId} == 1) {
        $Result{ErrId} = 2;               # 未使用局番(固定電話番号)
        $Result{TelEdit} = $TelCode;      # ResultFormat{TelEdit} (=TelNumber)なので入力値に差し替える
    } elsif ($ResultFormat{ErrId} == 2) {
        $Result{ErrId} = 3;               # 市内局番1桁目が[0 or 1](固定電話)
    } elsif ($ResultFormat{ErrId} == 3) {
        $Result{ErrId} = 4;               # 桁数不足(数字が10桁未満)
    } elsif ($ResultFormat{ErrId} == 4) {
        $Result{ErrId} = 5;               # 局番タイプに応じた桁数と不一致
    } else {
        $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
#//
#// 返却値 -- (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)
#//-------------------------------------------------------------------------------
sub FormatTelephone {
    my ($TelCode, $EditType) = @_;

    # 返却値
    my %Result = InitTelephone("Value");
    # GetTypeTelephone 返却値
    my %ResultType = InitTelephone("Type");

    my $strTelCode = "";  # Perlには引数に型指定が無いので空文字を連結して強制的に文字列型にする
    my $intEditType = 0;

    my $TelPattern = qr/^0\d{9,}$/;       # '0'始まりの数字文字列(10桁以上)
    my $EditTypePattern = qr/^[1-6]$/;    # '1' 〜 '6'(1文字)

    if (!defined($TelCode) || !defined($EditType)) {
        $Result{ErrId} = 9;
        return %Result;
    }

    # 空文字を連結して強制的に文字列型にする
    $strTelCode = $TelCode . "";

    # ['0'始まりの数字文字列(10桁以上)]のチェック
    # (番号翻訳(GetTypeTelephone)後に完全な桁数チェックを行なう。ここでは10桁未満のみNG)
    if ($strTelCode !~ /$TelPattern/) {
        $Result{ErrId} = 3;
        return %Result;
    }

    # EditTypeのチェック
    # 空文字を連結して強制的に文字列型とした上で
    # 1文字パターン('1'〜'6')の正規表現チェックを行なう
    if (($EditType . "") =~ /$EditTypePattern/) {
        $intEditType = $EditType * 1;    # 文字列型/数値型 共に強制的に数値型にする
        $Result{EditType} = $intEditType;
    } else {
        $Result{ErrId} = 6;
        return %Result;
    }

    %ResultType = GetTypeTelephone($strTelCode);  # 番号翻訳して電話番号の種別と桁区切り情報を取得する
    # 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} = $strTelCode;
    } else {
        # 0:OK  or  2:市内局番1桁目が[0 or 1](固定電話)
        if ($ResultType{TelType} == 2 && $intEditType >= 4) {
            # 携帯電話(070/080/090)で[3-3-5 桁区切り, 0x0-CDE-FGHJK]を指定された場合
            $Result{TelEdit} = InsertSeparator($strTelCode, $intEditType, 3, 3);
        } else {
            # 携帯電話(3-4-4桁区切り)を含め、他は返却値で区切りパターンが得られる
            # 固定電話では[市外局番桁数/市内局番桁数/加入者番号桁数(4)]が得られる
            if ($ResultType{Size2} == 0) {
                # 固定電話で、市内局番なし [ 0ABCDE-FGHJ ] (現在、この地域は存在しない)
                $Result{TelEdit}  = substr($strTelCode, 0, 6) . "-" . substr($strTelCode, 6);
            } else {
                $Result{TelEdit} = InsertSeparator($strTelCode, $intEditType, $ResultType{Size1}, $ResultType{Size2});
            }
        }

        if (length($strTelCode) != $ResultType{SizeAll}) {
            $Result{ErrId} = 4;  # 桁数エラー(局番タイプに応じた桁数と不一致)
        }
    }

    return %Result;
}


sub InsertSeparator {
    my ($TelCode, $EditType, $Size1, $Size2) = @_;

    my $Result = "";
    my $EditCode1 = substr($TelCode, 0, $Size1);        # 1st section :固定電話では市外局番(先頭'0')
    my $EditCode2 = substr($TelCode, $Size1, $Size2);   # 2nd section :固定電話では市内局番
    my $EditCode3 = substr($TelCode, $Size1 + $Size2);  # 3rd section :固定電話では加入者番号(末尾まで取り出す)

    if ($EditType == 1 || $EditType == 4) {       # 0AB-CDE-FGHJ
        $Result = $EditCode1 . "-" . $EditCode2 . "-" . $EditCode3;

    } elsif ($EditType == 2 || $EditType == 5) {  # 0AB(CDE)FGHJ
        $Result = $EditCode1 . "(" . $EditCode2 . ")" . $EditCode3;

    } elsif ($EditType == 3 || $EditType == 6) {  # (0AB)CDE-FGHJ
        $Result = "(" . $EditCode1 . ")" . $EditCode2 . "-" . $EditCode3;
    }

    return $Result;
}


#//-------------------------------------------------------------------------------
#// 電話番号タイプの取得 ( GetTypeTelephone )
#//
#// TelCode  -- 半角数字文字列(2桁以上, 先頭'0'固定)
#//             固定電話/携帯電話などの電話番号(途中までの内容でも可)
#//
#// 返却値 -- (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)
#//-------------------------------------------------------------------------------
sub GetTypeTelephone {
    my ($TelCode) = @_;

    # 返却値
    my %Result = InitTelephone("Type");

    my $strTelCode = "";  # Perlには引数に型指定が無いので空文字を連結して強制的に文字列型にする

    my $AreaCodeLength = 0;
    my $CityCodeLength = 0;
    my $CityCode1 = "";      # 市内局番の1桁目
    my $idx = 0;
    my $cnt = 0;
    my $num = 0;
    my $LinkValue = 0;
    my $TelType = 0;
    my $TelPattern = qr/^0\d+$/;       # '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]
    my @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]
        );

    if (!defined($TelCode)) {
        $Result{ErrId} = 9;
        return %Result;
    }

    # 空文字を連結して強制的に文字列型にする
    $strTelCode = $TelCode . "";

    # ['0'始まりの数字文字列(桁数制限なし)]のチェック
    # (桁数オーバーチェックは番号翻訳後に行なう)
    if ($strTelCode !~ /$TelPattern/) {
        $Result{ErrId} = 8;
        return %Result;
    }

    # ※ 番号翻訳テーブルをソースコード内に直に収録しているので
    #    JSONファイルの読み込み処理は必要ない。

    # 番号翻訳テーブルから局番情報(市外局番の桁数 or [携帯番号 等]のTelType情報)を取得する。
    # [TelCode]の長さが[局番桁数 未満]も受け入れているので『番号翻訳 途中』でのループ終了(TelType= -1)もある。
    $idx = 0;
    $TelType = -1;
    $AreaCodeLength = 0;
    for ($cnt = 1; ($cnt <= 5) && ($cnt < length($strTelCode)); $cnt++) {  # 番号翻訳テーブルはA〜Eコードの5段
        $num = substr($strTelCode, $cnt, 1) * 1;  # 電話番号の2桁目以降(1桁目は'0')を順次取り出す
        $LinkValue = $AreaCodeArray[$idx][$num];
        if ($LinkValue == 0) {   # 番号翻訳 終了(固定電話 未使用局番)
            $TelType = 1;
            $AreaCodeLength = 0;
            last;
        } elsif ($LinkValue < 0) {  # 番号翻訳 終了
            if ($LinkValue > -100) {
                # 固定電話の市外局番桁数(符号反転値) 実際の収録値[ -2 〜 -5 ]
                $TelType = 1;
                $AreaCodeLength = $LinkValue * (-1);  # 市外局番 桁数決定(先頭の "0" 含む)
            } else {
                # 携帯電話 等のTelType値(符号反転値 - 100) 実際の収録値[ -102 〜 -110 ]
                $TelType = ($LinkValue * (-1)) - 100;
            }
            last;
        } else {  # プラス値
            $idx = $LinkValue;  # 検索継続(収録値は NextIndex)
        }
    }

    # TelType に応じた桁区切りを設定する
    # 固定電話(TelType=1)では市外局番桁数(AreaCodeLength)に従って設定する
    # Size1 の値は[先頭'0'含む]
    $Result{TelType} = $TelType;
    if ($TelType == -1) {
        # 電話番号種別が不明(桁数不足で番号翻訳未了)
        $Result{ErrId} = 3;
    } elsif ($TelType == 1) {
        # 固定電話
        if ($AreaCodeLength == 0) {  # 未使用 局番
            $Result{ErrId} = 1;
        } elsif ($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 (length($strTelCode) < ($AreaCodeLength + 1)) {
                # [TelCode]が市内局番の桁位置までないので市内局番適否の判定不可⇒ OK で返す
                $Result{ErrId} = 0;
            } else {
                # FormatTelephone から呼ばれる場合は 10桁以上なので必ず判定可能
                $CityCode1 = substr($strTelCode, $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;
        }
    } else {
        # 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;
}