こんにちは、T田です。
今回は、JavaScriptで文字列から電話番号を抽出し、HTMLの<a>タグに変換する方法をお伝えします。

目次

  1. はじめに
  2. 抽出する電話番号の形式
  3. JavaScriptで抽出し、HTMLの<a>タグに変換
  4. おまけ
  5. おわりに

1.はじめに

スマートフォンのブラウザなどでwebページを見ていると、リンクがついている電話番号を見かけませんか?
そのリンクをクリックすると、電話を掛けることができて便利です。
しかし、電話番号ではないのに電話番号だと解釈されて数字にリンクがついてしまうことがあります。
これからお伝えする方法で、これを避けて電話番号のみにリンクをつけることができます。

2.抽出する電話番号の形式

まずは、どんな文字列を電話番号として抽出するかを決めます。
今回は以下の条件に当てはまる文字列を電話番号とみなすことにします。

  • 10文字以上の連続した半角数字
  • 区切り文字は「-(ハイフン)」もしくは半角スペースで、3文字以内
  • 数字の先頭に「+(プラス)」がある場合は電話番号に含める(国際電話番号表記)

3.JavaScriptで抽出し、HTMLの<a>タグに変換

以下の手順で処理を進めていきます。

イ.(先述した)条件に合致する文字列を、正規表現で抽出
ロ.区切り文字を除いて10文字以上の文字列か判定(10文字未満の文字列は変換しない)
ハ.抽出した文字列を用いて<a>タグ文字列を生成
ニ.抽出した文字列部分を、生成した<a>タグ文字列に置換

ではまず、ソースコード全体を見てみましょう。

function convertToAnchorTag( str )
{
	// 電話番号だと思われる文字列を抽出
	var phone_array = str.match( /\+?[0-9]+[\-\x20]?[0-9]+[\-\x20]?[0-9]+[\-\x20]?[0-9]+/g );
	var cursor = 0;
	for ( var i = 0; phone_array != null && i < phone_array.length; i++ ) {

		// ハイフンとスペースを削除
		var tmp = phone_array[i];
		tmp = tmp.replace( /[\-\x20]/g, '' );
		if ( tmp.length < 10 ) {
			// 10桁未満は電話番号とみなさない
			continue;
		}

		// aタグ文字列を生成
		var tag_a = '<a href="tel:' + tmp + '">' + phone_array[i] + '</a>';

		// 置換する電話番号の出現位置を取得
		var start = str.indexOf( phone_array[i], cursor );

		// 出現した電話番号を置換
		str = str.slice( 0, start ) + tag_a + str.slice( start + phone_array[i].length );
		cursor = start + tag_a.length;
	}

	return str;
}

引数strに文字列(Stringオブジェクト)を渡すと、その中の電話番号を<a>タグに変換して返すという関数です。
では順番に説明していきます。

イ.条件に合致する文字列を、正規表現で抽出

Stringオブジェクトのmatch()メソッドで電話番号文字列を抽出します。

function convertToAnchorTag( str )
{
	// 電話番号だと思われる文字列を抽出
	var phone_array = str.match( /\+?[0-9]+[\-\x20]?[0-9]+[\-\x20]?[0-9]+[\-\x20]?[0-9]+/g );
	var cursor = 0;
	for ( var i = 0; phone_array != null && i < phone_array.length; i++ ) {

正規表現は一見難しそうに見えますが、分解して見ていけば意外と簡単です。
こちらのサイトが分かりやすくてお勧めです。

match()メソッドの引数が正規表現なのですが、JavaScriptでは/で正規表現を囲みます。
末尾のgは正規表現のオプションで、「一致する全てを検索する」という意味です。
gオプションを指定しているので、変数phone_arrayには正規表現に一致する文字列が配列で格納されます。
※変数cursorは後ほどの処理で使用します。

では正規表現を以下のように分解してみましょう。

  • \+?
  • [0-9]+
  • [\-\x20]?

使用しているのはこの3パターンのみです。

\+?

これは先述した条件の「数字の先頭に「+(プラス)」がある場合は電話番号に含める」に該当します。
正規表現では+は特別な意味を持ちますので、\でエスケープしています。
末尾の?は、「直前の文字が0文字または1文字」という意味です。
まとめると、\+?は「+(プラス)が0文字または1文字」という意味になります。

[0-9]+

これは先述した条件の「連続した半角数字」に該当します。
0-9は半角数字を意味します。これを[]で囲むことで、「括弧([])内のいずれかに一致」という意味になります。
+は先述したように正規表現では特別な意味を持ち、「直前の文字が1文字以上」という意味です。
まとめると、[0-9]+は「0~9のいずれかが1文字以上」という意味になります。

[\-\x20]?

これは先述した条件の「区切り文字は「-(ハイフン)」もしくは半角スペース」に該当します。
正規表現では-も特別な意味を持ちますので、\でエスケープしています。
\x20は半角スペースをASCIIコードで表したものです。
まとめると、[\-\x20]?は「-(ハイフン)もしくは半角スペースが0文字または1文字」という意味になります。

まとめ

\+?[0-9]+[\-\x20]?[0-9]+[\-\x20]?[0-9]+[\-\x20]?[0-9]+の意味を日本語で表すと、「先頭にプラスが無いもしくは1文字あり、1文字のハイフンもしくは半角スペースが間に0~3文字含まれる半角数字の文字列」ということになります。

ロ.区切り文字を除いて10文字以上の文字列か判定(10文字未満の文字列は変換しない)

正規表現で抽出した電話番号文字列から、ハイフンと半角スペースを除いて文字数をカウントします。

		// ハイフンとスペースを削除
		var tmp = phone_array[i];
		tmp = tmp.replace( /[\-\x20]/g, '' );
		if ( tmp.length < 10 ) {
			// 10桁未満は電話番号とみなさない
			continue;
		}

Stringオブジェクトのreplace()メソッドで、正規表現を用いて文字列に含まれるハイフンと半角スペースを取り除きます。
取り除いた後の文字列が10文字に満たない場合は、電話番号でないとみなして処理しません。

ハ.抽出した文字列を用いて<a>タグ文字列を生成

抽出した電話番号文字列と、そこから区切り文字(ハイフンと半角スペース)を除いた文字列を用いて<a>タグを生成します。

		// aタグ文字列を生成
		var tag_a = '<a href="tel:' + tmp + '">' + phone_array[i] + '</a>';

電話番号をリンクにする際の形式は
<a href="tel:電話番号">リンク文字列</a>
なので、この形式に従って文字列を生成します。

ニ.抽出した文字列部分を、生成した<a>タグ文字列に置換

正規表現で抽出した電話番号文字列が引数strのどこにあるのか検索し、その電話番号文字列を生成した<a>タグに置換します。

		// 置換する電話番号の出現位置を取得
		var start = str.indexOf( phone_array[i], cursor );

		// 出現した電話番号を置換
		str = str.slice( 0, start ) + tag_a + str.slice( start + phone_array[i].length );
		cursor = start + tag_a.length;

StringオブジェクトのindexOf()メソッドで、抽出した電話番号文字列の出現位置を取得します。第2引数は検索開始位置です。
取得した出現位置を用いて、Stringオブジェクトのslice()メソッドによる文字列切り出し+文字列連結で置換処理を行います。
slice()メソッドの第1引数は切り出し開始位置、第2引数は切り出し終了位置です。また第2引数は省略でき、省略した場合は最後まで切り出します。

つまり23行目は、「抽出した電話番号文字列の出現位置以前の文字列」+「生成した<a>タグ文字列」+「抽出した電話番号文字列の末尾以降の文字列」の組合せにより、置換処理を行っています。
そして24行目では、indexOf()メソッドの検索開始位置を「抽出した電話番号文字列の出現位置+<a>タグ文字列の長さ」に設定しています。

4.おまけ

以下の<meta>タグを<head>タグ内に記述すると、ブラウザが自動で電話番号にリンクをつける機能を無効にすることができます。
<meta name="format-detection" content="telephone=no">

5.おわりに

今回は、JavaScriptで文字列から電話番号を抽出し、HTMLの<a>タグに変換する方法についてお伝えしました。
正規表現に苦手意識がある方は多いと思いますが、少しでもその意識が薄れていらっしゃれば幸いです。
ではまた次のブログでお会いしましょう!


<スポンサーリンク>