Hatena::ブログ(Diary)

babu_babu_babooのごみ箱

2018-04-16

電話番号の正規表現を割と真面目に考えることにした!自分の中ではもうこれは決定版か?

| 20:57

電話番号にはルールがある

http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/tel_number/number_shitei.html


切り取るにもルールを設けよう

    1. まず市外局番・市内局番・加入者番号を取り出したい
    2. 市内局番には括弧が付いているかもしれないのでそれを考慮
    3. 携帯番号にも対応させたい 090-1234-5678 or 090-123-4567
    4. フリーダイヤルにも対応させたい 0120-123-456 or 0120-12-3456
    5. ついでにIP電話とかにも対応させたい
    6. できる範囲でその番号が正しいのかチェックも兼ねたい

さて考えよ!>俺


で、2日間考えた。

先読み否定が良いものか?

先読み肯定がよいものか?


そのへんにあるものは、03(1234-5678 も通るだろう?

俺のは通さない!


で、完成した。

意地でも使おうっと。

  let ary = myreg.exec (str);
  if (ary)
    let [, ...tel] = ary;
    return tel.join ('-');
  else
    throw new Error ('電話番号の間違い') 
<!DOCTYPE html>
<html lang="ja">
<meta charset="UTF-8">
<title>Telephone</title>
<style>
table {
  font-size: x-small;
  width: 100%;
}
tr.red {
  background: #f88;
}

</style>

<body>
<table border="1"></table>


<script>
let ary = [
'5x4321',
'56-43215',
'2-4321',
'5-4321',
'65-4321',
'765-4321',
'8765-4321',

'(5)4321',
'(65)4321',
'(765)4321',
'(8765)4321',

'012345-6-7890',
'01234-5-6789',
'0123-45-6789',
'012-345-6789',
'03-2345-6789',
'0-12345-6789',
'09-2345-6789',

'0120-1-23456',
'0120-12-3456',
'0120-123-456',
'0120-1234-56',

'01234(5)6789',
'0123(45)6789',
'012(345)6789',
'03(2345)6789',
'11(2345)6789',

'090-1234-5678',
'090-1234-56789',
'090-12344-5678',
'0901-1234-5678',
'030-1234-5678',
'190-1234-5678',
'290-1234-5678',
'390-1234-5678',
'390/1234/5678',
'403-1234-567891',
];

//先読みで書式を選別し、利用できる番号で選別し、最後は緩く抜き出す

let
  hyphen = '\\-',
  num = '\\d+',
  local = '\\d{4}',
  delimiter = '\\D',
  OR = '|';
  
let
  type1 = '(?:' + num + hyphen + ')?' + num + hyphen + num, // x-x-x
  type2 = '(?:' + num + ')?\\(' + num + '\\)' + num,        // x(x)x
  format  = '(?:' + type1 + OR + type2 + ')';


let fixed1 = '(?:0[36]' + delimiter + ')?' + delimiter + '?[2-9][0-9]{3}' + delimiter + local;         //0x-2345-xxxx
let fixed2 = '(?:0[1-9][1-9]' + delimiter + ')?' + delimiter + '?[2-9][0-9]{2}' + delimiter + local;   //0xx-234-xxxx
let fixed3 = '(?:0[1-9][1-9][0-9]' + delimiter + ')?' + delimiter + '?[2-9][0-9]' + delimiter + local; //0xxx-23-xxxx
let fixed4 = '(?:0[1-9][1-9][0-9]{2}' + delimiter + ')?' + delimiter + '?[2-9]' + delimiter + local;   //0xxxx-2-xxxx

let fixed   = '^(?:'+ fixed1 + OR + fixed2 + OR + fixed3 + OR + fixed4 + ')$';                            //固定電話
let free    = '^0120' + hyphen + '(?:\\d{3}' + hyphen + '\\d{3}' + OR + '\\d{2}' + hyphen + local + ')$'; //フリーダイヤル
let mobile  = '^0[5789]0' + hyphen + '(?:[0-9]{3}' + hyphen + '\\d{5}' + OR + '\\d{4}' + hyphen + local + ')$';    //携帯電話
let phone = '(?=' + fixed + OR + free + OR + mobile + ')';


let phone_pattern   = '(?=' + format + ')' + '(?=' + phone + ')';
let pickup  = '(?:(' + num + ')' + delimiter + ')?' + delimiter + '?(' + num + ')' + delimiter + '(' + num + ')';//条件を経て最終的に抜き出す

let reg = new RegExp (phone_pattern + pickup);

//__________________________________

let table = document.querySelector ('table');

for (let a of ary) {
  let tr = table.insertRow (-1);
  let r = reg.exec(a);
  let cols = r
    ? ['o', a].concat (r)
    : ['x', a].concat ([,,,,]);
     
//  (r) ? console.log('o', a, r): console.log('x', a);
  if (! r)
    tr.className="red";  
  for (c of cols) {
    let td = tr.insertCell(-1);
    td.textContent = c;
  }
}

console.log(reg);
</script>

結局のところどこで妥協するかなんだろうな。

/(?=(?:(?:\d+\-)?\d+\-\d+|(?:\d+)?\(\d+\)\d+))(?=(?=^(?:(?:0[36]\D)?\D?[2-9][0-9]{3}\D\d{4}|(?:0[1-9][1-9]\D)?\D?[2-9][0-9]{2}\D\d{4}|(?:0[1-9][1-9][0-9]\D)?\D?[2-9][0-9]\D\d{4}|(?:0[1-9][1-9][0-9]{2}\D)?\D?[2-9]\D\d{4})$|^0120\-(?:\d{3}\-\d{3}|\d{2}\-\d{4})$|^0[5789]0\-(?:[0-9]{3}\-\d{5}|\d{4}\-\d{4})$))(?:(\d+)\D)?\D?(\d+)\D(\d+)/

原点に振り返ってみて思うこと。

なんで、市外・市内・加入番号に分けようとしたのだろう?

括弧付きの部分をハイフンに置き換えれば良いだけなのでは?

まぁ深く考えまい


電話番号の正規表現とは

国内は0から始まる10桁

携帯は11桁

番号の構成は、0・市外局番・市内局番・加入番号の順

市外局番の桁数と市内局番の桁数の和は5

市外局番が1桁は、3と6だけ

市外局番の2桁目は[1-9]、3桁目は0もある

市内局番は[2-9]で始まる

加入番号は4桁

市内局番は括弧が前後につける書式もある

携帯電話は、3・3.5桁が本当の書式で、3・4・4が普及している

フリーダイヤルは、4・3・3桁もあれば4・2・4もある(4・2・2・2なんてのも語呂合わせであるらしい)







JavaScript は、奥が深いと思っているが、正規表現もなかなかどうして。