Я работаю над функцией автоматической подсказки глоссария для сайта. Это позволит администратору вводить термины глоссария с соответствующими определениями, а затем эти слова будут преобразованы в триггеры всплывающей подсказки в любом месте, где они появляются на интерфейсе.

Вот метод, который я использую:

Все содержимое фильтруется перед выводом с помощью функции, которая ищет с помощью регулярного выражения терминов глоссария и помещает их в теги с классом, который затем выбирается javascript для обработки всплывающей подсказки при наведении курсора.

Что мне нужно сделать, и я не могу понять, так это включить соответствующее определение в качестве атрибута title в диапазон.

Вот мой код на данный момент: (исходные массивы - это просто примеры, в каждом намного больше записей)

function glossary_highlight( $content ) {
    $glossary = ['Lorem', 'Ipsum'];
    $definitions = ['Lorem is a type of crocodile', 'Ipsum is a kitchen utensil'];
    $patterns = [];
    foreach ($glossary as $term) {
        $patterns[] = '/\b' . $term . '\b/i';
    }
    $wrapper = '<span class="tooltip" title="XXXX">$0</span>';
    $wrapped = preg_replace($patterns, $wrapper, $content);
    return $wrapped;
}

Мне нужно заменить XXXX соответствующей записью в массиве $ definitions. Я не могу выполнить регулярное выражение в цикле foreach, потому что тогда он может начать добавлять интервалы в заголовки других интервалов, если определение содержит другой термин из глоссария и т. Д.

Желаемый эффект - учитывая $ content "Lorem ipsum dolor sit amet", возврат из этой функции должен быть:

<span class="tooltip" title="Lorem is a type of crocodile">Lorem</span> <span class="tooltip" title="Ipsum is a kitchen utensil">ipsum</span> dolor sit amet

Первым моим желанием было сделать что-то вроде:

$wrapper = '<span class="tooltip" title="' . $definitions[$key] . '">$0</span>';

Где $ key будет относиться к индексу рассматриваемого термина глоссария, но я не могу понять, как включить это в foreach.

Если я не могу понять все это на PHP, я думаю, я просто применю диапазон всплывающих подсказок и отправлю массив определений в javascript, чтобы добавить оттуда атрибут title, но я бы предпочел не разделять базовую задачу на два языка .. .

Я уверен, что здесь есть совершенно простой ответ, но мой мозг его не увидит! Кто-нибудь может помочь?

РЕДАКТИРОВАТЬ: спасибо lampyridae за его помощь, код ниже работает следующим образом:

function glossary_highlight( $content ) {
    $glossary = ['Lorem', 'Ipsum'];
    $definitions = ['Lorem is a type of crocodile', 'Ipsum is a kitchen utensil'];
    $patterns = [];
    foreach ($glossary as $term) {
        $patterns[] = '/\b' . $term . '\b/i';
    }
    $wrappers = [];
    foreach ($definitions as $definition) {
        $wrappers[] = '<span class="tooltip" title="' . $definition . '">$0</span>';
    }
    $wrapped = preg_replace($patterns, $wrappers, $content);
    return $wrapped;
}
1
Sark 28 Апр 2016 в 21:56

2 ответа

Лучший ответ

Я вижу два варианта:

  1. Запустите preg_replace один раз для каждого термина. Если тексты длинные, терминов много, и это делается в реальном времени, это может стать проблемой для производительности.
  2. Предоставьте множество замен, как вы это делаете для выкроек.

Я думаю, что номер 2 в целом будет быстрее и проще. Идея состоит в следующем:

$wrappers = [];
foreach ($definitions as $definition) {
    $wrappers[] = '<span class="tooltip" title="' . $definition . '">$0</span>';
}

… Затем используйте обертки:

$wrapped = preg_replace($patterns, $wrappers, $content);
0
lampyridae 28 Апр 2016 в 19:15

Я бы хранил ваши токены в едином ассоциативном массиве. Это просто чище и намного легче увидеть совпадения.

$words = [
    'lorem' => 'Lorem is a type of crocodile',
    'ipsum' => 'Ipsum is a kitchen utensil',
];

Затем строите выкройки. Обратите внимание на использование здесь привязки границы слова \ b, чтобы мы сопоставляли lorem, но не splorems.

$patterns = [];
foreach (array_keys($words) as $word) {
    $patterns[] = '/\b' . $word . '\b/i';
}

Затем используйте preg_replace_callback () для создания настраиваемой строки замены на лету:

$newContent = preg_replace_callback($patterns, function ($matches) use ($words) {
    return
        '<span class="tooltip" title="' .
        $words[strtolower($matches[0])] .
        '">' . $matches[0] . '</span>';
}, $content);
0
Alex Howansky 28 Апр 2016 в 19:24