Связывайте термины на странице со статьями Википедии на чистом JavaScript

Во время просмотра я наткнулся на этот блог сообщение об использовании Wikipedia API из JavaScript, чтобы связать один поисковый запрос с его определением. В конце сообщения в блоге автор упоминает возможные расширения, в том числе:

Плагин, который автоматически связывает термины со статьями Википедии.

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

Я знаю, что это может потребовать многого, но код выглядит так, как будто он почти готов, и я был бы готов добавить награду, если кто-то выполнит оставшуюся работу за этот виртуальный кредит ...;) Я также подозреваю, что это может быть из значение для нескольких других, поскольку я видел похожие запросы, но не работал (это просто JavaScript (и, следовательно, переносимая) библиотека / фрагмент).

Вот образец исходного исходного кода, я надеюсь, что кто-нибудь сможет добавить к нему или указать мне, что мне нужно было бы добавить, если бы я реализовал это сам (в этом случае я поделюсь кодом, если мне удастся собрать что-нибудь вместе).

<script type="text/javascript"><!--
var spellcheck = function (data) {
    var found = false; var url=''; var text = data [0];
    if (text != document.getElementById ('spellcheckinput').value)
        return;
    for (i=0; i<data [1].length; i++) {
        if (text.toLowerCase () == data [1] [i].toLowerCase ()) {
            found = true;
            url ='http://en.wikipedia.org/wiki/' + text;
            document.getElementById ('spellcheckresult').innerHTML = '<b style="color:green">Correct</b> - <a target="_top" href="' + url + '">link</a>';
        }
    }
    if (! found)
        document.getElementById ('spellcheckresult').innerHTML = '<b style="color:red">Incorrect</b>';
};

var getjs = function (value) {
    if (! value)
        return;
    url = 'http://en.wikipedia.org/w/api.php?action=opensearch&search='+value+'&format=json&callback=spellcheck';
    document.getElementById ('spellcheckresult').innerHTML = 'Checking ...';
    var elem = document.createElement ('script');
    elem.setAttribute ('src', url);
    elem.setAttribute ('type','text/javascript');
    document.getElementsByTagName ('head') [0].appendChild (elem);
};--></script>
<form action="#" method="get" onsubmit="return false"> 
<p>Enter a word - <input id="spellcheckinput" onkeyup="getjs (this.value);" type="text"> <span id="spellcheckresult"></span></p></form>

Обновление
Как отмечалось в комментариях, меня также интересовало время, которое потребуется для связывания всех слов, и то, как обрабатывать названия статей, состоящих из нескольких слов.

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

С другой стороны, это все будет на стороне клиента, и некоторая задержка в связи с условиями вполне приемлема.

В качестве альтернативы поиск терминов, над которыми наведена / выбрана мышь, также может быть приемлемым, но я не уверен, что это уменьшит или повысит сложность.


Обновление 2

'Pointy' пояснил ниже, что эта функциональность может быть достигнута путем изменения некоторых довольно стандартных сценариев выделения после получения списка тем статей от api.php?action=query&list=allpages.
Повторюсь: мы используем внутреннюю вики, поэтому список статей вероятно, ограниченный, однозначный и достаточно специфичный для предметной области, чтобы преодолеть некоторые ожидаемые проблемы при сопоставлении слов.

Поскольку до сих пор у нас было несколько хороших предложений и несколько работоспособных идей, я назначаю награду, чтобы посмотреть, смогу ли я получить несколько ответов по этому поводу ...


person Tim    schedule 27.02.2010    source источник
comment
Как сценарий должен знать, какие термины (слова? Фразы?) На странице содержат статьи в вики?   -  person Pointy    schedule 27.02.2010
comment
Предоставленный код проверяет, существует ли статья с данным именем в Википедии. Боюсь, это не имеет ничего общего со ссылками на термины на вашей странице со статьями вики.   -  person Douwe Maan    schedule 27.02.2010
comment
А, я понимаю - хорошо, если локальная вики поддерживает обратный вызов JSONP, тогда он, безусловно, мог бы сделать это таким образом. Мне интересно, как бы вы справились с многословными записями Wiki - как узнать, какие последовательности из нескольких слов нужно проверять? Проверить их все? Сколько времени займут все эти поисковые транзакции HTTP в вики?   -  person Pointy    schedule 27.02.2010
comment
Если он автоматически хочет связать все термины на своей странице со статьями вики, ему придется выполнять HTTP-запрос для каждого слова на странице ... Это нехорошо. К тому же, как говорит Пойнти, как скрипт найдет статьи Wiki, состоящие из нескольких слов? По сути, не будет.   -  person Douwe Maan    schedule 27.02.2010
comment
Что вы можете сделать, так это проверить, существует ли статья Wiki, когда пользователь наводит курсор мыши на термин более, чем, скажем, 2 секунды, поэтому ему нужно будет только сделать запрос для небольшого количества терминов. Но пользователь не сразу увидит, есть ли у кого-то связанная статья в Wiki, прежде чем он / она потратит время, чтобы удерживать указатель мыши на определенном сроке в течение 2 секунд ...   -  person Douwe Maan    schedule 27.02.2010
comment
Если задающий вопрос имеет контроль над Wiki, то одной из возможностей было бы создать Wiki API, который возвращал бы текущий словарь терминов. Таким образом, скрипт мог получить один большой блок слов, а затем просто искать их на каждой странице. Этот сценарий: tinyurl.com/6rk6ae можно адаптировать для добавления разметки.   -  person Pointy    schedule 27.02.2010
comment
К счастью, API уже предлагает api.php?action=query&list=allpages, см. en.wikipedia. org / w / Это можно дополнительно кэшировать, чтобы предотвратить загрузку списка для каждого запроса.   -  person Tim    schedule 27.02.2010
comment
С эстетической точки зрения это звучит ужасно. Кто-то, читающий страницу вашего сайта, будет иметь каждое слово со ссылкой на статью в Википедии ??? .... что отвлекает так же визуально, как привязка всех нетривиальных слов к рекламе   -  person Paul    schedule 28.02.2010
comment
@Paul: Нет. Мы используем внутреннюю вики с (очень) ограниченным набором статей, которые служат образовательной цели для наших студентов. Из-за этого ограниченного набора статей будут связаны только несколько слов. Это избавляет от необходимости выбирать, какие слова связывать, и как обрабатывать дубликаты (дубликатов просто не будет).   -  person Tim    schedule 28.02.2010


Ответы (2)


Возможно, поможет что-то вроде этого:

Предполагая очень простой HTML / текст, например:

<div id="theText">Testing the auto link system here...</div>

И два очень маленьких скрипта.

dictionary.js составляет список ваших условий. Я думал, что это можно сгенерировать на php, запросив базу данных статей, если хотите. Он также может быть загружен кросс-доменом (как он устанавливает window.termsRE). Если вам не нужно создавать список из базы данных, вы также можете вручную поместить его с помощью termlinker.js.

Этот код, который генерирует регулярное выражение, предполагает, что ваш массив terms содержит правильно отформатированные строки для соответствия с использованием регулярных выражений, поэтому обязательно используйте \\ для экранирования []\.?*+|(){}^&

// dictionary.js - define some terms
var terms = ['testing', 'auto link'];
window.termsRE = new RegExp("\\b("+terms.join("|")+")\\b",'gi');

termlinker.js - это просто простая замена поиска по регулярному выражению по определенным терминам. Это также может быть встроенный <script>. требует, чтобы dictionary.js был загружен перед запуском.

// termlinker.js - add some tags
var element = document.getElementById("theText");

element.innerHTML = element.innerHTML.replace(termsRE, function(term) {
  return "<a href='http://en.wikipedia.org/wiki/"+escape(term)+"'>"+term+"</a>";
}); 

Это просто ищет любые слова в массиве терминов и заменяет их ссылкой на термин. Конечно, он также будет соответствовать свойствам и значениям внутри HTML-тегов, что может немного нарушить вашу разметку.

Все вместе вы получите this (предварительный просмотр jsbin)


Использование API

Основываясь на минимальном случае из предыдущего, вот пример кода для использования API для получения списка слов напрямую и предварительный просмотр jsbin

// Utility Function
RegExp.escape = function(text) {
  if (!arguments.callee.sRE) {
    var specials = [
      '/', '.', '*', '+', '?', '|',
      '(', ')', '[', ']', '{', '}', '\\'
    ];
    arguments.callee.sRE = new RegExp(
      '(\\' + specials.join('|\\') + ')', 'g'
    );
  }
  return text.replace(arguments.callee.sRE, '\\$1');
};

// JSONP Callback for receiving the API
function receiveAPI(data) {
  var terms = [];
  if (!data || !data['query'] || !data['query']['allpages']) return false;  
  var pages = data.query.allpages
  for (var x in pages) {
    terms.push(RegExp.escape(pages[x].title));
  }
  window.termsRE = new RegExp("\\b("+terms.reverse().join("|")+")\\b",'gi');
  linkterms();
}  

function linkterms() {
  var element = document.getElementById("theText");

  element.innerHTML = element.innerHTML.replace(termsRE, function(term) {
    return "<a href='http://en.wikipedia.org/wiki/"+escape(term)+"'>"+term+"</a>";
  });
}


// the apfrom=testing can be removed, it is only there so that
// we can get some useful terms near "testing" to work with.
// we are limited to 500 terms for the purpose of this demo:
url = 'http://en.wikipedia.org/w/api.php?action=query&list=allpages&aplimit=500&format=json&callback=receiveAPI' + '&apfrom=testing';
var elem = document.createElement('script');
elem.setAttribute('src', url);
elem.setAttribute('type','text/javascript');
document.getElementsByTagName('head')[0].appendChild (elem);
person gnarf    schedule 09.03.2010
comment
Хорошее начало, есть ли шанс объединить это с вызовом json api.php?action=query&list=allpages или другим api.php запросом для получения заголовков тем? Я ищу что-то чистое Javascript, поэтому PHP мне не подходит ... (Как было сказано выше, я почти не знаю Javascript, поэтому мне нужно больше, чем начало ...) - person Tim; 10.03.2010
comment
Отличная работа, спасибо! С другой стороны, я обнаружил, что теперь мне нужно обновить наш локальный экземпляр вики для совместимости с API. - person Tim; 13.03.2010
comment
@gnarf - Есть ли способ обойти мы ограничены 500 условиями для целей этого демонстрационного -лимит? Я ищу имитировать полную функциональность Википедии автоматической гиперссылки на статьи Википедии. --- Большое спасибо. --- Я также начал публикацию с автоматической гиперссылкой на предопределенные статьи Википедии, чтобы не было перенаправления на страницы с неоднозначностью: Автоматическая гиперссылка на каждое вхождение определенного слова (или последовательности слов) на предопределенный URL (однозначный); но не показывать полный URL, сообщение, над которым еще нужно подумать. - person O0123; 11.02.2015

Аналогичного опыта можно добиться с помощью более общего сценария предварительного просмотра гиперссылок, такого как Linkz.ai. Просто сделайте гиперссылку на определение статьи в Википедии, и сценарий покажет ее определение.

  1. Зарегистрируйтесь для получения ключа API на странице https://linkz.ai.

  2. Добавьте на свои веб-страницы следующий фрагмент:

person Vittorio    schedule 24.05.2021
comment
Это хорошо. Я проверю его. - person Nikita; 25.05.2021