web-dev-qa-db-ja.com

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

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

「電話番号」と国ID(ISO国コードとしましょう)を指定して、標準のE.164国際形式の電話番号に変換したいと思います。

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

Java framework/library/utilityあなたはこれを達成することをお勧めしますか?

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

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

最後の1つは私のお気に入りです。これは、一部の人々が英国で番号を書き込む方法であり、+ 44を使用するか、0を使用する必要があることを意味します。

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

28
Vihung

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));
49
Collin Peters

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

文字と数字のマッピングは国間で一貫していますか?米国はこれを多く使用しますが(例:1800-GOT-MILK)、オーストラリアでは一例として、それはかなりまれです。あなたがしなければならないことは、それが変化する場合(そうでないかもしれない)、問題の国のために正しいマッピングを行っていたことを確認することです。異なるアルファベットを使用している国(たとえば、ロシアのCyrilicと以前の東側のブロック国)が何をしているのかわかりません。

あなたはあなたの解決策が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)で書き、そのように発音します。

un(1)、deux(2)、trois(3)、...

その

douze(12)、trente-quatre(34)、...

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

また、電話番号に内線番号を追加する人もいます。「ext」または同様の略語が使われている可能性があります。あなたはそれに応えたいですか?

ここにコードはありません。自問すべき問題と検討すべき問題のリスト。他の人が言ったように、一連の正規表現は上記のほとんどを実行できますが、結局のところ、電話番号フィールドは結局のところ(ほとんど)自由形式のテキストです。

10
cletus

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

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

これが同じ問題のある人の役に立つことを願っています。

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

3
arksoft

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

現在、電話番号文字列(ユーザーが入力したもの)とソース国のコンテキストおよびターゲット国のコンテキスト(番号のダイヤル元の国、および番号のダイヤル先の国)を取得する手作りのコードがあります。 -これはシステムに認識されています)。次の変換を段階的に実行します

  1. 番号からすべての空白を取り除く

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

  3. すべての句読点を取り除きます-先行する '+'が存在する場合はそのままにします(数値がすでに国際的な形式の場合)。

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

  5. 番号に国別コンテキストのローカルダイヤリングプレフィックスがあるかどうかを確認します。ソースコンテキストが英国の場合は、「0」で始まるかどうかを確認し、「+」で置き換えてから、対象国の国際ダイヤルコードを続けます。ソース国のローカルダイヤリングプレフィックスをルックアップテーブル(GB-> '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標準形式に変換され、変換はすべてソフトウェアで行われると思います。

1
Vihung

正直に言うと、基本のほとんどはすでにカバーされているようです。

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

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

1
Alnitak

電話番号を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

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

0
Henk

各国で電話番号の表記が異なるため、これは非常に困難な作業です。

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年前に廃止されました。

0