1

最大 2000 の用語を含む用語集があります (各用語集の用語は、1 つ、2 つ、または 3 つの単語 (空白またはダッシュで区切られたもの) で構成されます)。

現在、強調表示された用語を含む静的な HTML ページを生成するために、(より長い) HTML ドキュメント (最大 100 KB の HTML マークアップ) 内のすべての用語を強調表示するソリューションを探しています。

機能するソリューションの制約は次のとおりです。多数の用語集用語と長い HTML ドキュメント... (Python 内で) 効率的なソリューションの青写真は何でしょうか。

現在、lxml を使用して HTML ドキュメントを解析し、すべてのテキスト ノードを反復処理してから、各テキスト ノード内のコンテンツをすべての用語集用語と照合することを考えています。

クライアント側 (ブラウザー) のハイライトはオンザフライではありません。IE は、スクリプトのタイムアウトで実行時間の長いスクリプトについて不平を言うので、本番環境では使用できません。

もっと良いアイデアはありますか?

4

3 に答える 3

2

パーサーを使用してツリーを再帰的にナビゲートし、テキストで構成されたタグのみを置き換えることができます。
その際、考慮しなければならないことがいくつかあります:
- すべてのテキストを置換する必要があるわけではありません (例: インライン JavaScript)
- ドキュメントの一部の要素は解析する必要がない場合があります (例: 見出しなど)。

以下は、これを実現する方法の簡単で本番環境に対応していない例です。

html = """The HTML you need to parse"""
import BeautifulSoup

IGNORE_TAGS = ['script', 'style']

def parse_content(item, replace_what, replace_with, ignore_tags = IGNORE_TAGS):
    for content in item.contents:
        if isinstance(content, BeautifulSoup.NavigableString):
            content.replaceWith(content.replace(replace_what, replace_with, ignore_tags))
        else:
            if content.name not in ignore_tags:
                parse_content(content, replace_what, replace_with, ignore_tags)
    return item

soup = BeautifulSoup.BeautifulSoup(html)
body = soup.html.body
replaced_content = parse_content(body, 'a', 'b')

これにより、「a」が出現する場合は「b」に置き換えられますが、次の内容は残さ
れます。
- img、a... などのタグ内の参照
- タグ自体

もちろん、用語集によっては、単語の一部だけを別のものに置き換えないようにする必要があります。これを行うには、content.replace の代わりに正規表現を使用するのが理にかなっています。

于 2011-12-03T11:41:54.040 に答える
0

クライアント側の JavaScript を使用した強調表示が最適なオプションだと思います。サーバーの処理時間と帯域幅を節約し、さらに重要なことに、印刷や他の形式への変換など、不要なマークアップを必要としない人にとって、html をクリーンで使いやすい状態に保ちます。

タイムアウトを回避するには、ジョブをチャンクに分割し、setTimeout のスレッド関数で 1 つずつ処理します。このアプローチの例を次に示します

function hilite(terms, chunkSize) {

    // prepare stuff

    var terms = new RegExp("\\b(" + terms.join("|") + ")\\b", "gi");

    // collect all text nodes in the document

    var textNodes = [];
    $("body").find("*").contents().each(function() {
        if (this.nodeType == 3)
            textNodes.push(this)
    });

    // process N text nodes at a time, surround terms with text "markers"

    function step() {
        for (var i = 0; i < chunkSize; i++) {
            if (!textNodes.length)
                return done();
            var node = textNodes.shift();
            node.nodeValue = node.nodeValue.replace(terms, "\x1e$&\x1f");
        }
        setTimeout(step, 100);
    }

    // when done, replace "markers" with html

    function done() {
        $("body").html($("body").html().
            replace(/\x1e/g, "<b>").
            replace(/\x1f/g, "</b>")
        );
    }

    // let's go

    step()
}

次のように使用します。

$(function() {
    hilite(["highlight", "these", "words"], 100)
})

ご不明な点がございましたら、お知らせください。

于 2011-12-03T12:39:30.497 に答える
-1

用語集の各用語を調べてから、各用語について、正規表現を使用して HTML 内のすべての出現箇所を検索するのはどうですか? これらの出現のそれぞれを、背景色を持つようにスタイル設定される「ハイライト」クラスのスパンでラップされた用語に置き換えることができます。

于 2011-12-03T10:18:18.437 に答える