成形式のHTML文書に対して、タグを壊すことなく、
文書内の任意のキーワードに対してJavaScriptによる
タグ付けを行い、ハイライトする方法を考えてみます。
例えば、以下のようなHTML文書に対して
『div』と『fuga』にタグ付けを行い、
ハイライトすることを考えてみます。
<div class="hoge">
div
<span class="fuga">
fuga
</span>
</div>
タグを壊さないようにしつつ、指定のキーワードを
以下のようなハイライトのためのタグ
『<span class=”highlight”>キーワード</span>』
で括ります。
<div class="hoge">
<span class="highlight">div</span>
<span class="fuga">
<span class="highlight">fuga</span>
</span>
</div>
単純に置換すると、以下のようにタグにまで影響が及んで
しまうので、タグとマッチする部分は置換せずにそのまま。
タグ以外の領域でキーワードとマッチする場合だけ所定の置換を適用します。
<<span>div</span> class="hoge">
<span class="highlight">div</span>
<span class="<span>fuga</span>">
<span class="highlight">fuga</span>
</span>
</div>
具体的には以下のような感じで置換します。
var highlightHTML = function(html, word, cls){
if (!cls) { cls = 'highlight'; }
$.each(word, function(i,w){
html = html.replace(new RegExp('('+w+')|(<[0-9a-zA-Z]+(?:[ \t\n\f\r]+[^ \x00-\x1F\x7F"\'>/=]+(?:[ \t\n\f\r]*=[ \t\n\f\r]*(?:[^ \t\n\f\r"\'=><`]+|\'[^\x00-\x08\x0B\x0E-\x1F\x7F\']*\'|"[^\x00-\x08\x0B\x0E-\x1F\x7F"]*"))?)*[ \t\n\f\r]*/?>)|(<\/[0-9a-zA-Z]+[ \t\n\f\r]*>)', 'g'), function(){
for (var j=1,jMax=arguments.length-2; j<jMax; j++) {
if (arguments[j]) {
if (j == 1) {
return '<span class="'+cls+'">'+w+'</span>';
} else {
return arguments[j];
}
}
}
});
});
return html;
};
※$.eachをforやwhileで書き換えるとjQueryが不要になります。
以下のように使用します。
var html = 'HTML文書…';
var word = ['div', 'fuga'];
var highlighted = highlightHTML( html, word );
ハイライトするキーワードが日本語だったり、
ハイライトのためのspan要素のclass属性値を変更する場合は
以下のような形で使用します。
var html = 'HTML文書…';
var word = ['日本語キーワード', 'keyword'];
var highlighted = highlightHTML( html, word, 'myHighlightClass' );
HTML文書は成形式であり、キーワードはHTML文書内で
タグなどを示す特殊文字が全てエンティティ参照に
置き換えられているものと想定しています。
以下のような値は想定外になるため所望の動作をしません。
var html = '<div>1<5</div>';
var word = ['<'];
以下のような形になっていることを前提としています。
var html = '<div>1&lt;5</div>';
var word = ['&lt;'];
なお、タグ判別のための正規表現は
HTML5で省略できるタグにマッチする正規表現 – Qiita
より拝借しております。
お問い合わせについて
業務として技術コンサルティングやシステム設計・開発を行っております。
気になることがありましたらご相談下さい。
ご相談のみで完結する場合、コンサルティング費用の目安は
内容によりますが1時間で5千円〜1万円ていどです。
コンサルティングや開発を検討されるその前に、
まずはお気軽にコメントやメールでご連絡下さい。
※ご契約前のコメントやメールでのやりとりは無料です。