#024
posted on 2021.01.30 (Sat) 2022.09.22 (Thu)

正規表現でテキスト文内の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 ag2getParameterByName = 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 ag2idToEmbed = 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のURLを調べるための正規表現を作成。

  • テキスト内でYouTube(ホスト名が「youtube.com」か「youtu.be」)のURLになっている文字列を正規表現で判別。
  • テキスト本文ではなく、HTMLタグ内でhrefなど属性値としてURLが記述されている場合は除外させる。(URLの直前が「=”」となっていれば属性値と判断して除外する。正規表現の否定後読みを使用。)

※ Safariは正規表現の後読みに対応していないので、正規表現に後読みが含まれているとエラーになる。(後読みでの除外処理は諦めるか、ユーザーエージェントで分けて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 ag2changeToEmbed = 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 = ag2getParameterByName('v', url) ? ag2getParameterByName('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, ag2idToEmbed(youTubeId));
      }
    }
  }
  return txt;
};

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

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

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

対象文字列.replace(‘正規表現パターン’, ‘置換後の文字列’) : 指定した正規表現パターンが対象文字列内でマッチしたら、置換後の文字列に置き換える。「正規表現パターン」ではなく具体的な「文字列」を指定した場合、最初に表れたその文字列を「置換後の文字列」に置き換える。置き換え処理後の新しい文字列を返す。

 

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

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

const className = '置換処理をするテキストを内包する要素のクラス名';
//置換処理をする要素をクラス名で指定
const parentEle = document.getElementsByClassName(className),
	parentEleNum = parentEle.length;
//指定したクラス名を持つすべての要素で処理
for(let i = 0; i < parentEleNum; i++){
	//要素内の全HTMLを取得
	let originalHtml = parentEle[i].innerHTML;
	//HTML内にあるyoutubeの動画URLをすべて埋め込みiframeのコードに置換
	let newHtml = ag2changeToEmbed(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、失敗した場合はfalseを返す。

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

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

 

 

この記事のURL

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

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

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

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

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

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

この記事へのコメント

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

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