Java を使用して電話番号を国際形式 (E.164) に変換する最良の方法は何ですか?

StackOverflow https://stackoverflow.com/questions/187216

質問

Java を使用して電話番号を国際形式 (E.164) に変換する最良の方法は何ですか?

「電話番号」と国 ID (ISO 国コードとしましょう) が与えられた場合、それを標準の E.164 国際形式の電話番号に変換したいと思います。

手動で非常に簡単に実行できると確信していますが、すべての状況で正しく機能するかどうかはわかりません。

これを実現するにはどの Java フレームワーク/ライブラリ/ユーティリティをお勧めしますか?

追伸「電話番号」には、一般の人々が識別できるものであれば何でも構いません。

* (510) 786-0404
* 1-800-GOT-MILK
* +44-(0)800-7310658

最後のものが私のお気に入りです。これはイギリスで一部の人が自分の番号を書く方法で、+44 を使用するか、0 を使用する必要があることを意味します。

E.164 形式の番号はすべて数字で、完全な国際国コード (例: +44) を使用する必要があります。

役に立ちましたか?

解決

Googleは、電話番号を操作するためのライブラリを提供しています。 Androidで使用しているものと同じ

http://code.google.com/p/libphonenumber/

String swissNumberStr = "044 668 18 00"
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
try {
  PhoneNumber swissNumberProto = phoneUtil.parse(swissNumberStr, "CH");
} catch (NumberParseException e) {
  System.err.println("NumberParseException was thrown: " + e.toString());
}

// Produces "+41 44 668 18 00"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.INTERNATIONAL));
// Produces "044 668 18 00"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.NATIONAL));
// Produces "+41446681800"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.E164));

他のヒント

この種のことを書いた経験から言えば、100% の信頼性を保つことは非常に困難です。これを行うために、私たちが持っているデータの処理にはかなり優れた Java コードをいくつか書きましたが、すべての国に適用できるわけではありません。尋ねる必要がある質問は次のとおりです。

文字と数字のマッピングは国間で一貫していますか?米国ではこれを多く使用していますが(例:1800-GOT-MILK)、一例としてオーストラリアではこれはかなりまれです。必要なのは、問題の国が異なる場合 (異なる場合もあります)、その国に対して正しいマッピングを行っているかどうかを確認することです。異なるアルファベットを使用する国(ロシアのキリル文字や旧東側ブロック諸国など)が何をしているのかは知りません。

解決策が 100% ではないことを受け入れる必要があり、100% になることを期待すべきではありません。「最善の推測」アプローチを取る必要があります。たとえば、132345 が 1300 123 456 と同様にオーストラリアで有効な電話番号であることを知る実際の方法はありませんが、13xx 番号のパターンはこれら 2 つだけであり、これらは海外から発信できないことを知る方法です。

地域 (市外局番) を検証するかどうかも尋ねる必要があります。アメリカでは市外局番の2桁目が1か0というシステムを採用していると思います。かつてはそうだったかもしれませんが、今でも当てはまるかどうかはわかりません。いずれにせよ、他の多くの国には別のルールがあるでしょう。オーストラリアでは、固定電話と携帯電話の有効な市外局番は 2 桁です (最初の番号は 0)。08、03、04 はすべて有効です。01はそうではありません。それにはどう対応しますか?あなたは__したいですか?

書き込む桁数に関係なく、国によって使用される規則が異なります。「標準」以外のものを受け入れるかどうかを決める必要があります。これらはすべてオーストラリアでは一般的です。

  • (02) 1234 5678
  • 02 1234 5678
  • 0411 123 123 (04 1112 3456 は見たことがありません)
  • 131 123
  • 13 1123
  • 131 123
  • 1 300 123 123
  • 1300 123 123
  • 02-1234-5678
  • 1300-234-234
  • +44 78 1234 1234
  • +44 (0)78 1234 1234
  • +44-78-1234-1234
  • +44-(0)78-1234-1234
  • 0011 44​​ 78 1234 1234 (0011 は標準の国際電話番号です)
  • (44) 078 1234 1234 (一般的ではありません)

そして、それは私の頭のてっぺんにあります。一つの国のために。たとえば、フランスでは電話番号を数字のペアで書くのが一般的で (12 34 56 78)、彼らもそのように発音します。の代わりに:

アン(1)、ドゥ(2)、トロワ(3)、...

その

ドゥーズ(12)、トランテカトル(34)、...

そのレベルの文化の違いに対応したいですか?私はそうではないと思いますが、ルールを厳格にしすぎる場合に備えて、この質問は検討する価値があります。

また、電話番号に内線番号を追加する人もいます。おそらく「ext」または同様の略語が付けられます。それに応えたいですか?

申し訳ありませんが、ここにはコードがありません。自問すべき質問と考慮すべき問題のリストです。他の人が言ったように、一連の正規表現は上記の多くのことを実行できますが、最終的には電話番号フィールドは(ほとんど)自由形式のテキストになります。

これは私の解決策でした:

public static String FixPhoneNumber(Context ctx, String rawNumber)
{
    String      fixedNumber = "";

    // get current location iso code
    TelephonyManager    telMgr = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
    String              curLocale = telMgr.getNetworkCountryIso().toUpperCase();

    PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
    Phonenumber.PhoneNumber     phoneNumberProto;

    // gets the international dialling code for our current location
    String              curDCode = String.format("%d", phoneUtil.getCountryCodeForRegion(curLocale));
    String              ourDCode = "";

    if(rawNumber.indexOf("+") == 0)
    {
        int     bIndex = rawNumber.indexOf("(");
        int     hIndex = rawNumber.indexOf("-");
        int     eIndex = rawNumber.indexOf(" ");

        if(bIndex != -1)
        {
            ourDCode = rawNumber.substring(1, bIndex);
        }
        else if(hIndex != -1) 
        {               
            ourDCode = rawNumber.substring(1, hIndex);
        }
        else if(eIndex != -1)
        {
            ourDCode = rawNumber.substring(1, eIndex);
        }
        else
        {
            ourDCode = curDCode;
        }           
    }
    else
    {
        ourDCode = curDCode;
    }

    try 
    {
      phoneNumberProto = phoneUtil.parse(rawNumber, curLocale);
    } 

    catch (NumberParseException e) 
    {
      return rawNumber;
    }

    if(curDCode.compareTo(ourDCode) == 0)
        fixedNumber = phoneUtil.format(phoneNumberProto, PhoneNumberFormat.NATIONAL);
    else
        fixedNumber = phoneUtil.format(phoneNumberProto, PhoneNumberFormat.INTERNATIONAL);

    return fixedNumber.replace(" ", "");
}

これが同じ問題を抱えている人の助けになることを願っています。

自由に楽しんで使用してください。

回答ありがとうございます。元の質問で述べたように、私はそれが有効な(本物の)電話番号であるかどうかを判断するよりも、数値を標準形式にフォーマットすることにずっと興味があります。

現在、電話番号文字列(ユーザーが入力したもの)とソース国のコンテキストとターゲット国のコンテキスト(番号がダイヤルされている国、番号のある国)を受け取るいくつかの手作りのコードがありますダイヤルされています-これはシステムに認識されています)、次の変換をステップで行います

  1. 数字からすべての空白を削除

  2. すべてのアルファを数字に変換します-文字から数字へのルックアップテーブルを使用します(例:A->> 2、B-> 2、C->> 2、D->> 3)キーパッド用など(一部のキーパッドではこれらが異なる方法で配布されることを知りませんでした)

  3. すべての句読点を削除します-先行する「+」が存在する場合はそのままにします(番号が既に何らかの国際形式になっている場合)。

  4. 番号に国のコンテキストの国際ダイヤルプレフィックスがあるかどうかを判断します。ソースコンテキストが英国の場合、「00」で始まるかどうかを確認し、「+」に置き換えます。現在、「00」に続く数字の後に対象国の国際ダイヤルコードが続いているかどうかを確認しません。ルックアップテーブルでソース国の国際ダイヤルプレフィックスを検索します(例:GB-> '00'、US-> '011'など)

  5. 番号に国のコンテキストのローカルダイヤルプレフィックスがあるかどうかを確認します。ソースコンテキストが英国の場合、「0」で始まるかどうかを確認し、「+」に続いて対象国の国際ダイヤルコードを置き換えます。ルックアップテーブルでソース国のローカルダイヤルプレフィックス(GB-> gt; '0'、US-> '1'など)を検索し、ターゲット国の国際ダイヤルコードを別のルックアップで検索しますテーブル(例: 'GB' = '44'、US = '1')

これまでに投げたすべてのもので機能するようです-+44(0)1234-567-890状況を除いて-そのための特別なケースチェックを追加します。

それを書くのは難しくありませんでした-そして、私が遭遇した奇妙な例外ごとに特別なケースを追加できます。しかし、標準的な解決策があるかどうかを知りたいです。

電話会社は毎日この問題に対処しているようです。 PSTNを使用して番号をダイヤルする場合、一貫性のない結果が得られることはありません。たとえば、米国(携帯電話が固定電話と同じ市外局番を持っている場合、+ 1-123-456-7890または011-1-123-456-7890(011はUSおよび1は、米国の国際ダイヤルコードです)、1-123-456-7890(1は米国のローカルダイヤルプレフィックス)、または456-7890(私は当時123の市外局番であったと仮定します)これらのダイヤル番号は内部で同じE.164標準形式に変換され、変換はすべてソフトウェアで行われると想定しています。

正直なところ、ほとんどのベースはすでにカバーされているようです。

英国で時々(誤って)使用される+44(0)800形式は迷惑であり、数値の表示方法に関するITU-T勧告であるE.123に従って厳密に有効ではありません。 E.123のコピーを持っていない場合は、一見の価値があります。

それが価値があるのは、電話網自体がE.164を常に使用するとは限らないことです。多くの場合、PBXによって生成されたISDNシグナリング(またはスチーム電話を使用している場合はネットワーク)にフラグがあり、ダイヤルされている番号がローカル、国内、または国際かどうかをネットワークに通知します。

これは非常に困難な作業です。電話番号はほとんど各国で異なって書かれているためです。

以前はREGEXPのリストを保持し(19の形式をサポートしていました)、数値の3つの部分を解析し、それらの3つの部分を" + {1} {2} {3}"に変換しました。

正規表現をより具体的に並べ替えてから、最初に正規表現を取得して解析に成功します。

一部の国では、有効な電話番号として112を検証できますが、その前に国コードを貼り付けると、それはもう有効ではなくなります。他の国では112は検証できませんが、911は有効な電話番号として検証できます。

Qを7キーに、Zを9キーに配置する携帯電話を見てきました。 QとZを0キーに配置する電話機と、QとZを1キーに配置する電話機を見てきました。

昨日存在していた市外局番は今日存在しないかもしれませんし、その逆もあります。

北米の半分(国コード1)では、2桁目のルールは以前は市外局番の0または1でしたが、10年前に廃止されました。

電話番号をE.164にフォーマットするために利用できる標準ライブラリまたはフレームワークを知りません。

PBXが提供するcaller-idをE.164にフォーマットする必要がある当社製品に使用されるソリューションは、該当するすべての国のE.164フォーマット情報を含むファイル(データベーステーブル)を展開することです。 これには、プロダクションコードベースへの変更を必要とせずに、アプリケーションを(さまざまなPSTNネットワークのすべての奇妙なコーナーケースを処理するために)更新できるという利点があります。

このテーブルには、国コードごとの行と、市外局番の長さと加入者の長さに関する情報が含まれています。市外局番と加入者番号の長さで可能なバリエーションに応じて、国に複数のエントリがある場合があります。

テーブルの例としてニュージーランドPSTN(部分)ダイヤルプランを使用します。

CC  AREA_CODE  AREA_CODE_LENGTH  SUBSCRIBER  SUBSCRIBER_LENGTH
64                            1              7
64         21                 2              7
64        275                 3              6

あなたが説明したものと同様のことを行います。つまり、提供された電話番号から数字以外の文字を取り除き、全体の番号計画の長さ、外部アクセスコード、長距離/国際アクセスコードに関するさまざまなルールに基づいてフォーマットします。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top