文字列を置換するときに、そこにHTMLのタグが含まれていると予期せぬ結果を招くことがあります。
たとえば「class A class B class C」と表示されるHTMLコード
class A <i class="class">class B</i> class C
の文字列「class」だけを、<b>で囲む場合を考えます。このとき単純にString.replace()で
var text = 'class A <i class="class">class B</i> class C'; alert( text.replace( /class/g, '<b>$&</b>' ) );
とすると、class属性やその属性値まで置換されてしまい、
<b>class</b> A <i <b>class</b>="<b>class</b>"><b>class</b> B</i> <b>class</b> C
となってしまいます。これを出力すると「class A class="class">class B class C」のようになり、これは期待した結果とは異なります (出力例はW3C規約に反しない程度に修正してあります)。
よってこのような場合にはString.replace()の引数に関数を渡し、置換処理をカスタマイズします。
function Replacer( str, offset, s ) { var greater = s.indexOf( '>', offset ); var lesser = s.indexOf( '<', offset ); if( greater < lesser || ( greater != -1 && lesser == -1 ) ) { return str; } else { return '<b>' + str +'</b>'; } } var text = 'class A <i class="class">class B</i> class C'; var pattern = /class/g; alert( text.replace( pattern, Replacer ) );
関数Replacer()はパターンにマッチするごと呼び出されます。そしてマッチした文字列がタグの内部にある場合には、置換せずにそのまま文字列を返します。これによりタグ以外の文字列だけが置換されます。この結果は
<b>class</b> A <i class="class"><b>class</b> B</i> <b>class</b> C
となり、これは期待通り「class A class B class C」となります。
または発想を変えて、とりあえず置換した後に、タグ内に含まれるタグを削除する方法もあります。
text.replace( /(<[^<>]+)<b>([^<]+)<\/b>([^<>]+>)/g, '$1$2$3' );