This is a simple one: create the shortest browser script to change every appearance of force on a web page into horse. This script needs to be able to be pasted into the console and work on most modern browsers.

You must replace all occurences of the word force and conjugates of the word force (forcing, forced, reinforce). The cases must also be preserved.

You must not change any occurences which are not visible when the page is displayed in a browser. For example, meta tags or comments.


This is a fOrcE log. It makes people who touch it very forceful. Don't try forcing it.

This is a hOrsE log. It makes people who touch it very horseful. Don't try horsing it.

Unfortunately this is a Javascript only challenge. The shortest code wins.

  • 2
    \$\begingroup\$ Lol for xkcd XD \$\endgroup\$
    – ThreeFx
    Commented Sep 8, 2014 at 21:06
  • 9
    \$\begingroup\$ forcing doesn't contain the word force. \$\endgroup\$
    – Dennis
    Commented Sep 8, 2014 at 22:53
  • 2
    \$\begingroup\$ Either the question allows replacement of forc into hors - or it is the replacement of all the different conjugations of force into their horse versions. In the former case, we get things like "Reinhorsing", etc. In the latter, only forcing would be an exception. OP should clarify. \$\endgroup\$
    – absinthe
    Commented Sep 8, 2014 at 22:59
  • 2
    \$\begingroup\$ What about the equine equivalents of forcing, forcibly, forceps...? \$\endgroup\$ Commented Sep 8, 2014 at 23:03
  • 2
    \$\begingroup\$ "...any occurrences which are not visible when the page is displayed in a browser." is far too general. In particular, there are dozens or even hundreds of different ways to insert non-visible content into web pages. Perhaps you should just limit the exclusion to one or two specific types of tag. This prevents .innerHTML replace-all solutions, which I'm guessing is why you want the exceptions in the first place. \$\endgroup\$
    – COTO
    Commented Sep 9, 2014 at 1:01

3 Answers 3


175 bytes, ES5, XPATH

This tests successfully in the latest Firefox and Chrome. Criticism is welcome! This is my first golf swing, and I hope I'm doing it right.


The document.evaluate() method is supported by all major browsers except IE, which I hope satisfies the requirement for "most modern browsers". And because the XPath selector selects only text nodes, this ought to leave attributes, comments, namespaces, and other data not intended for display untouched without needing to check for each node's offsetParent.

Ungolfed version:

var force = document.evaluate('//text()', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

for (var i = 0; textNode = force.snapshotItem(i++); /* nothing */) {
    textNode.data = textNode.data.replace(
        function (full, $1, $2, $3) {
            return ($1 == 'f' ? 'h' : 'H' )
                + $2
                + ($3 == 'c' ? 's' : 'S' );

Or if I replace function / return with ECMA6 fat arrow notation, I can get it down to 163 characters.


This syntax currently only works in Firefox though, I think. Until more browsers adopt this syntax, the 175-byte solution above shall remain my official entry for the game.

  • \$\begingroup\$ Very interesting approach! There are two differences between our answers (which answer is behaving correctly is for the OP to judge): 1. Your regex will turn FORC into HORS. 2. Your code modifies all text nodes, while checking offsetParent filters out all tags with display:none style (which are not displayed in the browser). \$\endgroup\$
    – Dennis
    Commented Dec 27, 2014 at 3:58
  • \$\begingroup\$ @Dennis Thanks! Yeah, I can add (?=e|ing) to my regexp if OP deems it necessary. Regarding display: none, I interpreted "For example, meta tags or comments." to mean stuff that isn't text nodes should be left alone, while text nodes, including invisible nodes, should be changed. I would be interested to see the OP confirm his intentions though. \$\endgroup\$
    – rojo
    Commented Dec 27, 2014 at 4:11
  • \$\begingroup\$ @rojo Yep, you interpreted it correctly \$\endgroup\$
    – Beta Decay
    Commented Dec 28, 2014 at 11:24

ECMAScript 5, 248 233 193 191 182 bytes


Tested in Chrome and Firefox.

Ungolfed version

We should only modify visible TextNodes; URLs, attributes, etc. are not displayed in the browser. We can use a TreeWalker to find all of them. Visible TextNodes will be identified by checking if their ParentNode has a truthy offsetParent.1

// Create a TreeWalker that walks through all TextNodes. 

var walker = document.createTreeWalker(document, NodeFilter.SHOW_TEXT, null, false);

// While there are nodes left,

while(node = walker.nextNode())

// if the node is visible,


// search for the string "forc" (ignoring case)

        node.data = node.data.replace(/(f)(or)(c)/gi,

// and replace an uppercase/lowercase F/C with an uppercase/lowercase H/S.

            function(match, F, OR, C)
                return (F != 'f' ? 'H' : 'h') + OR + (C != 'c' ? 'S' : 's')

1 This is buggy in IE 9.

  • \$\begingroup\$ You know, you can drop this down to 193 bytes if you get rid of n=[],c=0, populating then looping back through n. Just do if(t.parentNode.offsetParent)t.data=t.data.replace etc. \$\endgroup\$
    – rojo
    Commented Dec 27, 2014 at 4:54

200 bytes, ES6

Here is an ES6 version. Run it in latest Firefox's web console.


I'll add the ungolfed version if requested :)

Here is the ungolfed version

var all = document.all;
for (var i = 0; i < all.length; i++) {
  if (all[i].parentNode && all[i].parentNode.offsetParent) {
    all[i].innerHTML = all[i].innerHTML.replace(/f[o0]rc(e|ing)/gi, function(matched) {
      var k = matched.split(""); // convert to array
      k[0] = k[0] == "F"? "H" : "h";
      k[3] = k[3] == "C"? "S" : "s";
      return k.join("");
  • 1
    \$\begingroup\$ I request an ungolfed version=P \$\endgroup\$
    – flawr
    Commented Sep 9, 2014 at 7:33
  • \$\begingroup\$ Wow... I thought these would be one-liners... Sort of replace('forc','hors') and that's it. Shows how much javascript I know... \$\endgroup\$
    – Beta Decay
    Commented Sep 9, 2014 at 11:58
  • 1
    \$\begingroup\$ 1. This approach doesn't work. innerHTML will change all occurrences inside visible elements, so if there's a comment inside, it will get touched as well. 2. One could argue that ES6 doesn't really work on most modern browsers. \$\endgroup\$
    – Dennis
    Commented Sep 9, 2014 at 12:29
  • \$\begingroup\$ As Dennis says above, this does not meet all of the requirements, therefore I have unaccepted this answer. \$\endgroup\$
    – Beta Decay
    Commented Sep 25, 2014 at 17:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.