電話番号の正規表現を割と真面目に考えることにした!自分の中ではもうこれは決定版か?
電話番号にはルールがある
http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/tel_number/number_shitei.html
切り取るにもルールを設けよう
-
- まず市外局番・市内局番・加入者番号を取り出したい
- 市内局番には括弧が付いているかもしれないのでそれを考慮
- 携帯番号にも対応させたい 090-1234-5678 or 090-123-4567
- フリーダイヤルにも対応させたい 0120-123-456 or 0120-12-3456
- ついでにIP電話とかにも対応させたい
- できる範囲でその番号が正しいのかチェックも兼ねたい
さて考えよ!>俺
で、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 = [ 'x:5x4321', 'x:56-43215123456789', 'x:56-43215', 'x:56-432', 'x:2-43215', 'o:5-4321', 'o: 5-4321', 'o:5-4321 ', 'o: 5-4321 ', 'o:65-4321', 'o:765-4321', 'o:8765-4321', 'o:(5)4321', 'o:(65)4321', 'o:(765)4321', 'o:(8765)4321', 'x:012345-6-7890', 'o:01234-5-6789', 'o:0123-45-6789', 'o:012-345-6789', 'o:03-2345-6789', 'x:0-12345-6789', 'x:09-2345-6789', 'x:0120-1-23456', 'o:0120-12-3456', 'o:0120-123-456', 'x:0120-1234-56', 'o:0120-123-456', 'o: 0120-123-456', 'o:0120-123-456 ', 'o: 0120-123-456 ', 'o:01234(5)6789', 'o:0123(45)6789', 'o:012(345)6789', 'o:03(2345)6789', 'x:11(2345)6789', 'o:090-1234-5678', 'x:090-1234-56789', 'x:090-12344-5678', 'x:0901-1234-5678', 'x:030-1234-5678', 'x:190-1234-5678', 'x:290-1234-5678', 'x:390-1234-5678', 'x:390/1234/5678', 'x:403-1234-567891', 'o:090(8765)4321', 'o: 090(8765)4321', 'o:090(8765)4321 ', 'o: 090(8765)4321 ', 'o:0120(34)5678', ]; //先読みで書式を選別し、利用できる番号で選別し、最後は緩く抜き出す 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[1-9][1-9][0-9]{2}' + delimiter + ')?' + delimiter + '?[2-9]' + delimiter + local; //0xxxx-2-xxxx let fixed2 = '(?:0[1-9][1-9][0-9]' + delimiter + ')?' + delimiter + '?[2-9][0-9]' + delimiter + local; //0xxx-23-xxxx let fixed3 = '(?:0[1-9][1-9]' + delimiter + ')?' + delimiter + '?[2-9][0-9]{2}' + delimiter + local; //0xx-234-xxxx let fixed4 = '(?:0[36]' + delimiter + ')?' + delimiter + '?[2-9][0-9]{3}' + delimiter + local; //0x-2345-xxxx let fixed = fixed1 + OR + fixed2 + OR + fixed3 + OR + fixed4; //固定電話 let free = '0120' + delimiter + '(?:\\d{3}' + delimiter + '\\d{3}' + OR + '\\d{2}' + delimiter + local + ')'; //フリーダイヤル let mobile = '0[5789]0' + delimiter + '(?:[0-9]{3}' + delimiter + '\\d{5}' + OR + '\\d{4}' + delimiter + local + ')'; //携帯電話 let phone = fixed + OR + free + OR + mobile; let phone_pattern = '^\\s*(?=' + format + ')' + '(?=(?:' + phone + ')\\s*$)'; let pattern = phone_pattern; let pickup = '(?:(' + num + ')' + delimiter + ')?' + delimiter + '?(' + num + ')' + delimiter + '(' + num + ')';//条件を経て最終的に抜き出す let reg = new RegExp (pattern + pickup); //__________________________________ let table = document.querySelector ('table'); for (let a of ary) { let tr = table.insertRow (-1); let ox; [,ox, a] = /^(o|x)\:(.*)/.exec (a); let r = reg.exec(a); let cols = r ? [ox, 'o', a].concat (r) : [ox, 'x', a].concat ([,,,,]); if (cols[1]!==ox) tr.className="red"; for (c of cols) { let td = tr.insertCell(-1); td.textContent = c; } } console.log(reg); </script>
結局のところどこで妥協するかなんだろうな。
/^\s*(?=(?:\d+\-)?\d+\-\d+|(?:\d+)?\(\d+\)\d+)(?=(?:(?:0[1-9][1-9][0-9]{2}\D)?\D?[2-9]\D\d{4}|(?:0[1-9][1-9][0-9]\D)?\D?[2-9][0-9]\D\d{4}|(?:0[1-9][1-9]\D)?\D?[2-9][0-9]{2}\D\d{4}|(?:0[36]\D)?\D?[2-9][0-9]{3}\D\d{4}|0120\D(?:\d{3}\D\d{3}|\d{2}\D\d{4})|0[5789]0\D(?:[0-9]{3}\D\d{5}|\d{4}\D\d{4}))\s*$)(?:(\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 は、奥が深いと思っているが、正規表現もなかなかどうして。
追記
ちょっと修正した。
0120(34)5678
090(8765)4321
の形式も通るようにした。