getStringRange を書いてみました。がっ!しかし、バグがウジャウジャしていそう!

node::textContents と、range::toString で得られる値が、常に同じなのか確かめていない。
IE未対応、そしてまだまだ、問題あり。

<!DOCTYPE html>
<title></title>
<head>
<script>
// getStringRange (root /*Element*/, serachReg /*RegExp*/ )
(function () {

  // n で指定されたノードを範囲とするテキストを返す
  var createGetRangeText = function (doc) {
    var r = doc.createRange ();
    return function (n) {
      r.selectNode (n);
      return r.toString ();
    };
  };
  

  // root の範囲内で、呼ばれるたびテキストノードだけを順次返す
  var createGetNextTextNode = function (root) {
    return function (node) {
      var m;
      do {
        if (! (node = (m = node).firstChild))
          while (! (node = m.nextSibling))
            if (root == (m = m.parentNode))
              return null;

      } while (node && 3 !== node.nodeType)

      return node;
    };
  };
  
  // p で示される位置まで、テキストノードの文字をカウントしながら移動する
  // ノードとその文字のオフセットを返す
  var createMovePointer = function  (root) {
    var pointer = 0;
    var node = root;
    var nextTextNode = createGetNextTextNode (root);
    var getRangeText = createGetRangeText (root.ownerDocument);
    var text;

    return function (p) {
      var m;

      while (pointer <= p) {
        if (node = nextTextNode (node)) {
          m = pointer;
          text = getRangeText (node);
          if (p <= (pointer += text.length))
            return { element: node, offset: p - m };
        }
        else return null;
      }
      
      return { element: node, offset: text.length - pointer + p };
    };
  };

  // 正規表現でヒットした文字の index からテキストノードを得て範囲を貯める
  var getRange = function (root, searchReg) {
    var range, obj, words;
    var result = [ ];
    var doc = root.ownerDocument;
    var getRangeText = createGetRangeText (doc);
    var movePointer  = createMovePointer (root);
    var text = getRangeText (root); // = root.textContents

    while (words = searchReg.exec (text)) {
      range = doc.createRange ();
      
      // start 
      obj = movePointer (words.index);
      range.setStart (obj.element, obj.offset);
      
      // end
      obj = movePointer (words.index + (words.toString ().length));
      range.setEnd (obj.element, obj.offset);

      result.push (range);
    };

    return result.length ? result: null;
  };

  //_______
  
  this.getStringRange = getRange;
})();





//_______

window.onload = function() {
  var ranges = getStringRange (document.body, /最[東西南北]端|[^、].[町村]/g);
  var selection = getSelection ();

 
  if (ranges.length) {
    selection.removeAllRanges ();
    for (var i = 0, r; r = ranges[i++]; )
      selection.addRange (r);
  }
}
</script>

</head>
<body>
<h1><em>洋野町</em>(ひろのちょう)</h1>
<h2>プロフィール</h2>
<ul>
<li>
洋野町は、岩手県の中で、最北端に位置し、東側は太平洋に面しています。
<li>
「リアス式海岸」といえば、「三陸」を連想する人もいると思います。残念ながら洋野町は、
そこより北に位置し、範囲に含まれません。そしてこれといって特徴がありません。
<li>
人口は、7月31日現在で、19420人です。(100歳を超えなくても、所在不明な人はいます。予測)
<li>
数年前に、隣の大野村と合併しました。それまでは、種市町(たねいちまち)と呼ばれていました。
<li>
「南部もぐり」と呼ばれ、潜水技術が発展しており、日本中の海洋建設の基礎工事現場などで、本町出身者の方々は活躍しています。
<li>本州最東端は、洋野町から南に100kmほどの地点にある半島です。

</ul>