#024
posted on 2021.01.30

正規表現でテキスト文内のYouTubeの動画URLを埋め込みコードに自動置換。

正規表現でテキスト文の中にあるYouTubeの動画のURLを取得、URLから動画IDを抽出して<iframe>の埋め込みコードに自動置換する関数の作成。

 

  1. テキスト内にあるYouTubeのURLをすべて取得して配列化。
  2. 動画のURLかどうか判定。
  3. 動画のURLから動画のID(クエリのパラメータ名vの値)部分を取得。
  4. 動画のIDを記述した<iframe>の埋め込みコードを作成。
  5. 動画のURLの部分を<iframe>の埋め込みコードに置換。
  6. すべての該当URL箇所を置換処理したテキスト全文で元のテキスト全文を書き換え。

 

JavaScriptで実装する場合

1. 動画IDを取得する関数を作成

動画のURLのクエリ内からパラメーターvの値(動画のID)の部分を取得する関数を作成する。

name(パラメーター名)を第1引数、url(任意のURL)を第2引数に指定して、URLのクエリから指定したパラメーターの値を取得する関数。

const getParameterByName = function(name, url){
  //ULRをクエリで分割して配列化
  let queryString = url.split('?');
  //URLにクエリがあった場合
  if(queryString.length >= 2){
    //複数のパラメーターがあれば分割して配列化
    let paras = queryString[1].split('&');
    //指定したパラメーターの値を取得
    for(let i = 0; i < paras.length; i++){
      //パラメーターを名前と値で分割
      let eachPara = paras[i].split('=');
      //パラメーター名が指定のものと一致したら値を返して関数処理を終了
      if(eachPara[0] == name) return eachPara[1];
    }
  }
  //URLに指定のパラメーターが無い場合はnullを返す
  return null;
};

対象文字列.split(‘区切り文字’) : 区切り文字で分割して配列で返す。区切り文字が無ければ対象文字列をそのまま返す。

 

2. 動画IDを埋め込みコードに置換する関数を作成

動画IDを引数にしてYouTubeのiframe形式の埋め込みコードにする関数を作成する。

allow属性はYouTubeの公式埋め込みのデフォルト設定からautoplayのみ削除。

パラーメーターに関する公式ドキュメンド

const idToEmbed = function(id){
  let ytIframe = '<iframe src="https://www.youtube.com/embed/'+id+'" frameborder="0" allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
  return ytIframe;
};

 

3. テキスト内のYouTubeのURLを取得する正規表現リテラルを作成

ホスト名がYouTube(「youtube.com」か「youtu.be」)になっているURLを正規表現で判定・取得する。

HTMLタグ内のhrefなど属性値に記述されている場合は除外させる。(テキスト文内でURLの直前が「=”」の場合は、否定後読みを使用して除外。)

※ Safariは正規表現の後読みに対応していない。正規表現に後読みが含まれているとエラーになるので、後読みを使用しないかユーザーエージェントで分ける。

const ytUrlRegExp = /(?<!=\")\b(?:https?):\/\/(?:www\.)?(?:youtube\.com|youtu\.be)\/[\w!?/+\-|:=~;.,*&@#$%()'"[\]]+/g;

//否定後読みで除外を使用しない場合
const ytUrlRegExp = /\b(?:https?):\/\/(?:www\.)?(?:youtube\.com|youtu\.be)\/[\w!?/+\-|:=~;.,*&@#$%()'"[\]]+/g;

変数 = /正規表現パターン/フラグ : 正規表現オブジェクトnew RegExp()と同じ。JavaScriptでリテラルに宣言する場合には、「/」をデリミタに使う。
(?<!パターン) : 否定後読み。検索文字列の直前に指定したパターンが無い場合だけマッチ。検索文字列の直後に指定したパターンが無い場合だけマッチさせる(否定先読み)には「(?!パターン)」。

[] : 角括弧に含まれるいずれか1文字にマッチ。角括弧内で使用できるメタ文字(「-」「^」「\」「]」のみ)はエスケープが必要。

\w : [a-zA-Z_0-9]と同じ。すべての半角英数字とアンダーバーにマッチ。

* : 直前の文字を0回以上繰り返したものにマッチ。

| : 左右辺の文字列のいずれかにマッチ。

\b : 単語境界。単語の先頭か末尾にマッチ。文字列の中の単語の境界にマッチさせるパターン。

(?:パターン) : グループがマッチしても配列に格納や後方参照をさせないグループ化。

? : 直前の文字が0個か1個の場合にマッチ。

+ : 直前の文字を1回以上繰り返したものにマッチ。

g : (global)フラグ。2番目、3番目…以降にマッチする部分も検索して配列として返す。

 

 

4. テキスト内のYouTubeの動画URLを探して置換処理する関数を作成

上記の関数と正規表現を使ってテキスト内の全ての動画URLを埋め込みに自動置換する関数を作成する。

URLにクエリが含まれている場合は、パラメーター名vの値の部分(動画ID)を取得してiframeの埋め込みコードに置換。クエリが無い場合には動画のURLである「watch」がパスに含まれているかを判定して動画ID部分を取得する。

const changeToEmbed = function(txt){
  //テキスト内からホスト名がyoutubeのURLにマッチする文字列をすべて取得
  let urls = txt.match(ytUrlRegExp);
  //youtubeのURLがあった場合
  if(urls){
    //すべてのURLをチェックして置換処理
    for(let i = 0; i < urls.length; i++){
      let url = urls[i],
          youTubeId,
          replaceRegExp;
      //URLにクエリがある場合
      if(url.match(/\?/) != null){
        //URLからID(パラメーター名vの値)の部分を抽出
        youTubeId = getParameterByName('v', url) ? getParameterByName('v', url) : false;
      }else if(url.match(/(youtube\.com\/watch|youtu\.be)/) != null){
      //URLにクエリが無く、動画のURLかショートコードの場合
        //URLからIDの部分を抽出
        youTubeId = (/(?:https?):\/\/(?:www\.)?(?:youtube\.com\/watch|youtu\.be)\/(.+)/g).exec(url)[1];
      }
      //テキスト内の該当URLの箇所をiframeのコードに置換
      if(youTubeId){
       replaceRegExp = new RegExp('(?<!=\")(?:'+url.replace('.', '\\.').replace('?', '\\?')+')');
       txt = txt.replace(replaceRegExp, idToEmbed(youTubeId));
      }
    }
  }
  return txt;
};

対象文字列.match(‘正規表現リテラルまたはRegExpオブジェクト’) : 対象文字列内にマッチする文字列があれば、その文字列を返す。無ければnullを返す。

要素.innerHTML : 要素が包括するHTMLを返す。

(‘正規表現リテラルまたはRegExpオブジェクト’).exec(‘対象文字列’) : 対象文字列内のマッチした文字列を配列で返す。無ければnullを返す。

 

 

5. 置換するテキスト要素のクラス名を指定して関数を実行

置換処理をしたいテキストを内包するHTML要素のクラス名を指定して、上記の関数を実行する。

const className = '置換処理をするテキストを内包する要素のクラス名';
//置換処理をする要素をクラス名で指定
const parentEle = document.getElementsByClassName(className);
//指定したクラス名を持つすべての要素で処理
for(let i = 0; i < parentEle.length; i++){
	//要素内の全HTMLを取得
	let originalHtml = parentEle[i].innerHTML;
	//HTML内にあるyoutubeの動画URLをすべて埋め込みiframeのコードに置換
	let newHtml = changeToEmbed(originalHtml);
	//置換処理したHTMLでparentEleの中身を書き換え
	parentEle[i].innerHTML = newHtml;
}

 

 

PHPで実装する場合

上記の内容をPHPだけで実装する場合。

function ag2id_to_embed($id){
  $yt_iframe = '<iframe src="https://www.youtube.com/embed/'.$id.'" frameborder="0" allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
  return $yt_iframe;
}
function ag2get_the_parameter($name, $url){
  //ULRをクエリで分割
  $query_string = explode('?', $url);
  //URLにクエリがあった場合
  if(count($query_string) >= 2){
    //複数のパラメーターがあれば分割
    $paras = explode('&', $query_string[1]);
    //$parasから指定のパラメーターを取得
    for($i = 0; $i < count($paras); $i++){
      //パラメーターを名前と値で分割
      $each_para = explode('=', $paras[$i]);
      //パラメーター名が指定のものと一致したら値を返して関数処理を終了
      if($each_para[0] == $name) return $each_para[1];
    }
  }
  //指定のパラメーターが無ければfalseを返す
  return false;
}
function ag2change_to_embed($txt){
  $look_behind = '(?<!=\")';//否定後読み
  $yt_url_regex = '/'.str_replace('/','\\/',$look_behind).'(?:https?):\/\/(?:www\.)?(?:youtube\.com|youtu\.be)\/[\w!?\/+\-|:=~;.,*&@#$%()\'"[\]]+/';
  $yt_watch_regex = '/(?:https?):\/\/(?:www\.)?(?:youtube\.com\/watch|youtu\.be)\/(.+)/';
  //テキスト内からyoutubeのURLにマッチする文字列をすべて取得
  preg_match_all($yt_url_regex, $txt, $urls, PREG_SET_ORDER);
  if($urls){
    $yt_url_regex = [];
    //すべてのURLをチェックして動画のURLなら置換
    for($i = 0; $i < count($urls); $i++){
      $yt_id = false;
      $url = $urls[$i][0];
      //クエリがある場合
      if(preg_match('/\?/', $url)){
        //URLから動画IDを抽出
        $yt_id = ag2get_the_parameter('v', $url) ? ag2get_the_parameter('v', $url) : false;
      }else if(preg_match('/youtube\.com\/watch|youtu\.be/', $url)){
      //URLにクエリが無い場合
        //動画のURLかショートコードならURLのID部分を抽出
        preg_match($yt_watch_regex, $url, $yt_id, PREG_OFFSET_CAPTURE);
        $yt_id = $yt_id[1][0];
      }
      //テキスト内の該当URLの置換処理
      if($yt_id){
        $yt_url_regex[$i] = '/'.str_replace('/','\\/',$look_behind).preg_quote($url,'/').'/';
        $txt = preg_replace($yt_url_regex[$i], ag2id_to_embed($yt_id), $txt);
      }
    }
  }
  return $txt;
}

$text = '自動置換の処理をしたいテキスト全文。';
$text = ag2change_to_embed($text);

explode(‘区切り文字’, ‘対象文字列’) : 区切り文字で分割して配列で返す。区切り文字が無ければ対象文字列をそのまま返す。

str_replace(‘置換前文字列’, ‘置換後文字列’, ‘対象文字列’) : 対象文字列内のすべての置換前文字列を置換後文字列で置換。文字列ではなく配列の指定も可能。返り値はすべての該当箇所を置換した後の対象文字列。

preg_match_all(‘正規表現’, ‘対象文字列’, ‘変数’, ‘フラグ’) : 対象文字列内のすべてのマッチした文字列をフラグで指定した方法で配列で変数に格納。返り値はマッチすれば1、しなければ0。

preg_match(‘正規表現’, ‘対象文字列’, ‘変数’, ‘フラグ’) : 対象文字列内の最初にマッチした文字列(全体と後方参照できるグループ化部分)を配列で変数に格納。返り値はマッチすれば1、しなければ0。

preg_quote(‘文字列’, ‘デリミタ’) : 文字列中にある正規表現で使われる特殊文字と指定したデリミタの前にバックスラッシュを挿入する。エスケープ処理された文字列を返す。

preg_replace(‘正規表現’, ‘置換後文字列’, ‘対象文字列’) : 対象文字列内のすべてのマッチした文字列を置換後文字列で置換。文字列ではなく配列の指定も可能。返り値はすべての該当箇所を置換した後の対象文字列。str_replace()関数の方が処理は速い。

 

 

この記事をシェア
この記事のURL

https://memo.ag2works.tokyo/post-921/

コピー
この記事のタイトル

正規表現でテキスト文内のYouTubeの動画URLを埋め込みコードに自動置換。 | memo メモ [AG2WORKS]

コピー
この記事のリンクタグ

<a href="https://memo.ag2works.tokyo/post-921/" target="_blank" rel="noopener">正規表現でテキスト文内のYouTubeの動画URLを埋め込みコードに自動置換。 | memo メモ [AG2WORKS]</a>

コピー
※ フィールドをクリックでコピーするテキストの編集ができます。

この記事へのコメント

コメントの書き込みはまだありません。

  • コメント内のタグはエスケープ処理され、文字列として出力されます。
  • セキュリティーのため、投稿者のIPアドレスは取得されます。
  • 管理者が内容を不適切と判断したコメントは削除されます。
  • このフォームにはスパム対策として、Googleの提供するreCAPTCHAシステムが導入されています。
    (Google Privacy Policy and Terms of Service.)