開発中のサイトの 1 つで検索機能を完成させようとしています。検索結果には一致した項目の内容の抜粋しか表示されないため、検索結果内の検索用語を強調表示し、それらの検索用語を実際に含むテキストの一部のみを表示する必要があります。
私がやろうと思ったのは、データベースからコンテンツ全体を取得し、それを使用preg_replace
して検索用語の前後に要素を挿入<span>
し、同時に用語の前後の最初の 10 単語だけを抽出することです。したがって、これはその正規表現部分です。
(?:.*?)((?:\w+\W+){0,10})('.implode('|', $terms).')((?:\W*\w+\W+){0,10})
基本的に、非キャプチャ サブパターンを使用して、検索用語の前の最初の 10 語を除くすべてのテキストを「破棄」し、用語の前の 10 語、次に用語自体、次の 10 語を取得しようとします。
の置換テキストは次のpreg_replace
とおりです。
\\1<span class="search-term search-term-content">\\2</span>\\3...
検索語は、複数の列のインデックスMySQL
のMATCH()...AGAINST()
を介して検索されています。MyISAM FULLTEXT
ただし、上記の正規表現は 1 つの列にのみ適用されます (この列を、上記の正規表現を使用する列と呼びましょうcontent
)。
したがって、私の問題は、列ではなく他の列で一致するたびに、content
上記の正規表現がcontent
列からすべてのテキストを削除することです。これは、(?:.*?)
最初のサブパターンが一致し続け、次のサブパターンが見つからないためです。
この副作用なしで正規表現の本来の目的を実装する他の方法があるかどうか疑問に思っていました。私は現在preg_match_all
、検索語とその前後の10語を一致させるために単純に使用することを考えています. すべての一致を繰り返し処理し、プレビュー テキストを手動で作成します。はい、これは適切な解決策ですが、正規表現の経験が浅いため、これに対する解決策を見つけようとする方がよいと思いました。
アップデート
contents
2 つ以上の検索語を入力すると、空白になるだけであることに気付きました。それ以外は、完璧に機能します。なぜこれが起こっているのか、今ではわかりません。
更新 2
エコーpreg_last_error()
すると、このエラーが発生しますPREG_BACKTRACK_LIMIT_ERROR
。私は単語new
とpost
検索語を使用します。
var_dump
正規表現の Aと用語はこれを示しています。
@(?:.*?)((?:\w+\W+){0,10})(new|post)((?:\W*\w+\W+){0,10})@i
array
0 => string 'new' (length=3)
1 => string 'post' (length=4)
更新 3
以前Regex Coach
は一致するパターンを順を追って説明していましたが、一致するものが見つからなかった後、バックトラックが多すぎるようです(new|post)
。ターゲット テキストは、単純にランダムな 3 段落の lorem ipsum です。このタスクには、より良い正規表現を見つける必要があると思います。
更新 4
サブパターンを使用Once-Only
すると、問題が解決します。Once-Only
詳細はわかりませんが、PHPマニュアルを読み直して、サブパターンがバックトラックが多すぎるのに役立つという部分を読んだだけです。これは新しい正規表現です:
(?:.*?)((?>\w+\W+){0,10})('.implode('|', $terms).')((?:\W*\w+\W+){0,10})
しかし、より良い正規表現の提案はまだ受け付けています。ありがとう!