Find a string of text in an element and wrap some span tags round it

Another approach, split by keyword and join with the updated html.

$("h2:contains('cow')").html(function(_, html) {
   return html.split('cow').join("<span class='smallcaps'>cow</span>");
});

Note: I haven't tested this, but I'm assuming this would perform worse than doing a replace, but figure I would include anyways for informative purposes


$("h2:contains('cow')").html(function(_, html) {
   return html.replace(/(cow)/g, '<span class="smallcaps">$1</span>');
});

http://jsfiddle.net/w5ze6/1/


Here is a variation on @undefined's answer, which loops through an array of items:

var barnyardArray = [
    'cow',
    'horse',
    'chicken',
    'hog',
    'goat',
    'goose',
    'duck',
    'llama'
];

$.each(barnyardArray, function (index, value) {
    $("p:contains(" + value + ")").html(function (_, html) {
        var regex = new RegExp(value, 'g');
        return html.replace(regex, '<span class="smallcaps">' + value + '</span>');
    });
});

You usually want to match some arbitrary text in a case insensitive way. Sometimes, search queries contain characters that are special regex metacharacters and must be escaped before compiling the pattern.

Use a solution like

var words = ["cows", "c++", "$var$"];
$("h2").html(function(_, html) {
   return html.replace(new RegExp(words.map(function(x) { 
       return x.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
     }).join('|'), "gi"), '<span class="smallcaps">$&</span>')
});
span { color: red}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h2>We have cows on our farm</h2>
<h2>C++ Apps $var$</h2>

Note that here, a regex will look like /cows|c\+\+|\$var\$/gi, where + and $, special regex metacharacters, are escaped, and the alternatives are ORed with the | alternation operator.

Also, note that there is no need of any outer parentheses as the default group is Group 0 that holds the whole match, and the backreference to Group 0 in JavaScript regex is $&. Thus, the replacement is always done with the search word in the exact case as it was found in text.

Note that in case you need to match whole words only, you would need special boundaries, either \b (if the search words always consist of letters, digits or _) or (\W|^) / (?!\w) (if there can be special characters):

var words = ["cows", "c++", "$var$"];
$("h2").html(function(_, html) {
   return html.replace(new RegExp("(\\W|^)(" + words.map(function(x) { 
       return x.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
     }).join('|') + ")(?!\\w)", "gi"), '$1<span class="smallcaps">$2</span>')
});
span { color: red}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h2>We have cows in our farm cowshed</h2>
<h2>C++ Apps $var$ in $var$moretext</h2>