jsで文中に複数回出現するURLをハイパーリンクのaタグで囲む
概要など
-
やりたいこと
自作のチャットサービス等で、メッセージ内のURL部分をハイパーリンク化し、
それ以外は任意ノード (<span>
等 ) で囲みたい。
でも.replace()
とか.outerHTML
とか使った直接文字列置換はしたくない -
実現イメージ
"あいうえおhttps://example.com/ やらhttps://google.com/ など"
...といった文字列から、以下の様なノードを構成<div> <span>あいうえお</span> <a href="https://example.com/">https://example.com/</a> <span> やら</span> <a href="https://google.com/">https://google.com/</a> <span> など</span> </div>
-
留意点
URLの正規表現は適当にググったものを使ってます。
( ※ 何が限りなく正解に近いのか、よくわかっていないので )
「javascript URL 正規表現」 で検索
実処理
URL検出の正規表現を使いつつも、
.split()
でセパレーターを消さない分割方法 を足がかりにするのが楽かな~と思いました
{
const _text = "この文章にはいくつかの https://example.com や https://www.google.co.jp/ などの URL が含まれています。";
const _urlRegex = /(https?:\/\/[\w/:%#\$&\?\(\)~\.=\+\-]+)/;
const _nodes = ((_chatMsg)=>{
let _parts = _chatMsg.split(_urlRegex);
let _nodeArr = [];
_parts.forEach(_txt=>{
if(_txt.length <= 0){
return;
}
else if(URL.canParse(_txt)){
const _a = document.createElement("a");
_a.href = _txt;
_a.target = "_blank";
_a.textContent = _txt;
_nodeArr.push(_a);
}else{
const _span = document.createElement("span");
_span.textContent = _txt;
_nodeArr.push(_span);
}
});
return _nodeArr;
})(_text);
console.log(_nodes);
// 後は _nodes.forEach() とかで、レンダリングしたい ノードに対して .appendChild() すれば良さそう
}
個人的ポイント
-
.split()
でセパレータを含める
MDN - String.prototype.split() > RegExp を使った分割でセパレーターの一部を結果に含める正規表現部分を
()
で囲むことで、セパレーター部分を含めた分割配列を得られます。
( ※ この記事を書くまで知りませんでした orz ){ const _txt = "あいうえおhttps://example.com/ やらhttps:google.com/ など"; let _result_1 = _txt.split(/(https?:\/\/[\w/:%#\$&\?\(\)~\.=\+\-]+)/); let _result_2 = _txt.split(/https?:\/\/[\w/:%#\$&\?\(\)~\.=\+\-]+/); console.log(_result_1); // (5) ['あいうえお', 'https://example.com/', ' やら', 'https:// google.com/', ' など'] console.log(_result_2); // (3) ['あいうえお', ' やら', ' など'] }
-
URL判定部分 ( 正規表現部分とで、URL判定を実質2回しちゃってますが… )
MDN - URL: canParse()
URL.canParse()
判定に任せることで、
旧来のtry-catch
でnew URL();
を囲う方法から脱却できたちなサポート状況
Can I use - URL.canParse