5

制御できない HTML ファイルがいくつかあります。したがって、構造やマークアップを変更することはできません。

これらの HTML ファイルごとに、別のアルゴリズムに基づいて単語のリストが検索されます。これらの単語は、HTML のテキストで強調表示する必要があります。たとえば、HTML マークアップが次の場合:

<p>
Monkeys are going to die soon, if we don't stop killing them. 
So, we have to try hard to persuade hunters not to hunt monkeys. 
Monkeys are very intelligent, and they should survive. 
In fact, they deserve to survive.
</p>

単語のリストは次のとおりです。

are, we, monkey

結果は次のようになります。

<p>
    <span class='highlight'>Monkeys</span> 
    <span class='highlight'>are</span> 
going to die soon, if 
    <span class='highlight'>we</span> 
don't stop killing them. 
So, 
    <span class='highlight'>we</span> 
have to try hard to persuade hunters 
not to hunt 
    <span class='highlight'>monkeys</span>
. They 
    <span class='highlight'>are</span> 
very intelligent, and they should survive. 
In fact, they deserve to survive.
</p>

強調表示アルゴリズムは次のようにする必要があります。

  1. 大文字と小文字を区別しない
  2. JavaScript で記述されている (これはブラウザ内で行われます) (jQuery は歓迎されます)
  3. 高速であること (ほぼ 800 ページの特定の本のテキストに適用可能であること)
  4. ブラウザの有名な「スクリプト停止」ダイアログが表示されない
  5. ダーティ HTML ファイルに適用可能 (無効な HTML マークアップのサポートなど、たとえば、閉じられていないなど)

    要素) (これらのファイルの一部は MS Word の HTML エクスポートであり、私が意味する「汚い」を理解していると思います!!!)

  6. 元の HTML マークアップを保持する必要があります (マークアップの削除、意図した単語を要素内にラップする以外のマークアップの変更、ネストの変更はありません。強調表示された単語を除いて、HTML は編集の前後で同じに見える必要があります)。

私が今までやってきたこと:

  1. JavaScriptの単語のリストを次のような配列で取得します["are", "we", "monkey"]
  2. ブラウザでテキスト ノードを選択しようとしました (現在は問題があります)。
  3. 各テキスト ノードをループし、各テキスト ノードに対して、リスト内の各単語をループして検索し、要素内にラップします。

ここでオンラインで視聴できることに注意してください(ユーザー名: demo@phis.ir、パス: demo)。また、現在のスクリプトは、ページのソースの最後に表示されます。

4

5 に答える 5

4

単語を文字列に連結|し、その文字列を正規表現として解釈してから、出現箇所をハイライト タグで囲まれた完全一致に置き換えます。

于 2012-11-05T12:42:23.883 に答える
2

次の正規表現は、この例で機能します。多分あなたはそこからそれを拾うことができます:

"Monkeys are going to die soon, if we don't stop killing them. So, we have to try hard to persuade hunters not to hunt monkeys. Monkeys are very intelligent, and they should survive. In fact, they deserve to survive.".replace(/({we|are|monkey[s]?}*)([\s\.,])/gi, "<span class='highlight'>$1</span>$2")
于 2012-11-05T12:30:34.747 に答える
2

与えられた問題はとても興味深いものでした。これが私が思いついたものです:

  • 何らかのプラグインを使用する (または自分で作成する) ことで、要素が表示されたときに通知を受け取ることができます
  • その要素 text-nodes を解析し、単語自体から派生した一意の css-class 名を使用して、各単語を span 要素にラップします
  • これらのユニークなクラス名に css-rules を追加する機能を追加

サンプル: http://jsbin.com/welcome/44285/


コードは非常にハックで、最新の Chrome でしかテストできませんが、私にとってはうまく機能し、確実に構築できます。

/**
 * Highlighter factory
 *
 * @return Object
 */
function highlighter() {
  var
    me = {},
    cssClassNames = {},
    cssClassNamesCount = 0,
    lastAddedRuleIndex,
    cbCount = 0,
    sheet;

  // add a stylesheet if none present
  if (document.styleSheets.length === 0) {
    sheet = document.createElement('style');
    $('head').append(sheet);
  }

  // get reference to the last stylesheet
  sheet = document.styleSheets.item(document.styleSheets.length - 1);

  /**
   * Returns a constant but unique css class name for the given word
   * 
   * @param String word
   * @return String
   */
  function getClassNameForWord(word) {
    var word = word.toLowerCase();
    return cssClassNames[word] = cssClassNames[word] || 'highlight-' + (cssClassNamesCount += 1);
  }

  /**
   * Highlights the given list of words by adding a new css rule to the list of active
   * css rules
   * 
   * @param Array words
   * @param String cssText
   * @return void
   */
  function highlight(words, cssText) {
    var
      i = 0,
      lim = words.length,
      classNames = [];

    // get the needed class names
    for (; i < lim; i += 1) {
      classNames.push('.' + getClassNameForWord(words[i]));
    }

    // remove the previous added rule
    if (lastAddedRuleIndex !== undefined) {
      sheet.deleteRule(lastAddedRuleIndex);
    }

    lastAddedRuleIndex = sheet.insertRule(classNames.join(', ') + ' { ' + cssText + ' }', sheet.cssRules.length);
  }

  /**
   * Calls the given function for each text node under the given parent element
   *
   * @param DomElement parentElement
   * @param Function onLoad
   * @param Function cb
   * @return void
   */
  function forEachTextNode(parentElement, onLoad, cb) {
    var i = parentElement.childNodes.length - 1, childNode;
    for (; i > -1; i -= 1) {
      childNode = parentElement.childNodes[i];
      if (childNode.nodeType === 3) {
        cbCount += 1;

        setTimeout(function (node) {
          return function () {
            cb(node);
            cbCount -= 1;
            if (cbCount === 0 && typeof onLoad === 'Function') {
              onLoad(me);
            }
          };
        }(childNode), 0);

      } else if (childNode.nodeType === 1) {
        forEachTextNode(childNode, cb);
      }
    }
  }

  /**
   * replace each text node by span elements wrapping each word
   *
   * @param DomElement contextNode
   * @param onLoad the parent element
   * @return void
   */
  function add(contextNode, onLoad) {
    forEachTextNode(contextNode, onLoad, function (textNode) {
      var
        doc = textNode.ownerDocument,
        frag = doc.createDocumentFragment(),
        words = textNode.nodeValue.split(/(\W)/g),
        i = 0,
        lim = words.length,
        span;

      for (; i < lim; i += 1) {
        if (/^\s*$/m.test(words[i])) {
          frag.appendChild(doc.createTextNode(words[i]));
        } else {
          span = doc.createElement('span');
          span.setAttribute('class', getClassNameForWord(words[i]));
          span.appendChild(doc.createTextNode(words[i]));
          frag.appendChild(span);
        }
      }

      textNode.parentNode.replaceChild(frag, textNode);
    });
  }

  // set public api and return created object
  me.highlight = highlight;
  me.add = add;

  return me
}

var h = highlighter();
h.highlight(['Lorem', 'magna', 'gubergren'], 'background: yellow;');

// on ready
$(function ($) {
  // using the in-view plugin (see the full code in the link above) here, to only
  // parse elements that are actual visible
  $('#content > *').one('inview', function (evt, visible) {
    if (visible) {
      h.add(this);
    }
  });

  $(window).scroll();
});
于 2012-11-05T20:01:50.480 に答える
1

私が一緒にハッキングしたLinguigiというライブラリを試すことができます

var ling = new Linguigi();

ling.eachToken(/are|we|monkey/g, true, function(text) {
    return '<span class="highlight">' + text + '</span>';
});
于 2012-11-05T12:37:52.243 に答える
0

jQueryを使用している場合は、これを試してください。

$('* :not(:has(*))').html(function(i, v) {
  return v.replace(/searchString/g, '<span class="highlight">searchString</span>');    
});




$('* :not(:has(*))') will search for each node having no child elements and replace the html string in it with given string warapped in your HTML.

私の迅速で汚い解決策は、このブログの魂に基づいています。

http://wowmotty.blogspot.in/2011/05/jquery-findreplace-text-without.html

彼のソリューションは div セレクターに対して機能し、テキストのみを置き換えます。私の場合は、innerHTML 文字列を置き換えようとします。

これを試して、何ができるか教えてください。面白そう。

于 2012-11-05T12:43:24.053 に答える