User:Khanson/compare2texts.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
Documentation for this user script can be added at User:Khanson/compare2texts. |
// <nowiki>
//Скрипт для поиска совпадающих подстрок в двух текстах
//Этот код выполняется в начале.
if (wgAction == 'edit' || wgAction == 'submit'){
addOnloadHook(XRomix_Compare2texts_OnLoad)
}
/////////////////////////////////////////////////////////////////////////////
function XRomix_Compare2texts_OnLoad(){
//Этот код выполнится после загрузки страницы
var toolbar = document.getElementById('toolbar')
var textbox = document.getElementById('wpTextbox1')
if (!textbox || !toolbar) return
addToolbarButton("Сравнение", XRomix_Compare2texts, 'btnXRomix_Compare2texts', 'Сравнение двух текстов', "");
//Adds a text button to edit toolbar
function addToolbarButton(name, onclick, id, tooltip, accesskey){
var toolbar = document.getElementById('toolbar');
if (!toolbar) return;
var newBtn = document.createElement('input');
newBtn.type = 'button';
newBtn.style.background = '#adbede';
newBtn.style.height = '22px';
newBtn.style.verticalAlign = 'middle';
if (name) newBtn.value = name;
if (onclick) newBtn.onclick = onclick;
if (id) newBtn.id = id;
if (tooltip) newBtn.title = tooltip;
if (accesskey) newBtn.accessKey = accesskey;
toolbar.appendChild(newBtn);
return newBtn;
}
}
/////////////////////////////////////////////////////////////////////////////
function insertAfter(parent, node, referenceNode) {
parent.insertBefore(node, referenceNode.nextSibling);
}
/////////////////////////////////////////////////////////////////////////////
function XRomix_Compare2texts(){
XRomix_CreateNewTextbox();
}
/////////////////////////////////////////////////////////////////////////////
function XRomix_CreateNewTextbox(){
//var input = document.getElementById('wpSummary')
var input = document.getElementById('wpTextbox1')
if (!input) return
var el = document.getElementById('XRomix_wpTextbox2')
if (el) {
removeElementById('XRomix_wpTextbox2');
return;
}
var el = document.createElement('span')
el.id = 'XRomix_wpTextbox2';
el.style.marginLeft = '3px'
input.parentNode.insertBefore(el, input.nextSibling)
el.innerHTML = '<p>Текст в окне ниже не будет сохранён на сервер.\
<input type="button" value="Выполнить сравнение" onclick="XRomix_btnCompare2texts_Compare()">\
<input type="button" value="Следующее соответствие" onclick="XRomix_btnCompare2texts_CompareNext()">\
<br/><span id="XRomix_ComparedText"></span></p><textarea cols="80" rows="15" id="XRomix_Textbox2" name="XRomix_Textbox2"> \
</textarea> \
<input id="XRomix_h1" name="XRomix_h1" type="hidden" value="" /> \
<input id="XRomix_h2" name="XRomix_h2" type="hidden" value="" /> ';
//Вспомогательные функции
function removeChildrenRecursively(node)
{
if (!node) return;
while (node.hasChildNodes()) {
removeChildrenRecursively(node.firstChild);
node.removeChild(node.firstChild);
}
}
function removeElementById(nodeId) {
document.getElementById(nodeId).parentNode.removeChild(
document.getElementById(nodeId));
}
}
/////////////////////////////////////////////////////////////////////////////
function XRomix_Compare2texts_Compare(mode){
//////////////////////////////////////
// Переменные для функции
var XRomix_maxP1; //позиция максимально совпадающих фрагментов
var XRomix_maxP2;
var XRomix_max1;//длина максимвльно совпадающих фрагментов
var XRomix_max2;
var XRomix_len1;//длина текущего соответствия для checkCompareLength
var XRomix_len2;
var XRomix_s1// тексты для сравнения. в них знаки препинания и прочие различия удалены, но число и позиция символов сохранена
var XRomix_s2
var wpTextbox1=document.getElementById('wpTextbox1');
if(!wpTextbox1) return;
if(mode=="first"){
var s= wpTextbox1.value;
XRomix_s1=prepareText(s, true); //см. ниже
}else if (mode=="next"){
var h1=document.getElementById('XRomix_h1');
XRomix_s1 = h1.value;
}
var wpTextbox2=document.getElementById('XRomix_Textbox2');
if(!wpTextbox2) return;
if(mode=="first"){
var s= wpTextbox2.value;
XRomix_s2=prepareText(s, false); //см. ниже
}else if (mode=="next"){
var h2=document.getElementById('XRomix_h2');
XRomix_s2 = h2.value;
}
getMaxSameText(); //см.ниже
//alert("Совпадение1: "+wpTextbox1.value.substr(XRomix_maxP1, XRomix_max1))
//alert("Совпадение2: "+wpTextbox2.value.substr(XRomix_maxP2, XRomix_max2))
var sovp1=wpTextbox1.value.substr(XRomix_maxP1, XRomix_max1);
var sovp2=wpTextbox2.value.substr(XRomix_maxP2, XRomix_max2);
if(XRomix_max2>3){
selectInTextArea(wpTextbox1, sovp1);
selectInTextArea(wpTextbox2, sovp2);
setSelectionRange(wpTextbox1, XRomix_maxP1, XRomix_maxP1+XRomix_max1);
setSelectionRange(wpTextbox2, XRomix_maxP2, XRomix_maxP2+XRomix_max2);
wpTextbox1.focus();
var label = document.getElementById('XRomix_ComparedText');
label.innerHTML="<i><font color='blue'>"+sovp2+"</font></i>";
}else{
var label = document.getElementById('XRomix_ComparedText');
label.innerHTML="<font color='blue'>Совпадений не найдено</font>";
//alert("Совпадений не найдено");
}
var s=XRomix_s1;
var left=s.substr(0, XRomix_maxP1);
var right=s.substr(XRomix_maxP1+XRomix_max1);
var sp=generateSpaces(XRomix_max1);
var XRomix_s1=left+sp+right;
if(s.length!=XRomix_s1.length){
alert("Длина строк не совпадает");
}
var h1=document.getElementById('XRomix_h1');
h1.value=XRomix_s1;
var h2=document.getElementById('XRomix_h2');
h2.value=XRomix_s2;
//////////////////////////////////////
//Выполняет замену подстроки s1 на s2 в строке s. Сама строка s при этом не изменяется
function replace(s, s1, s2){
var p=s.indexOf(s1);
if (p<0) return;
var left=s.substr(0, p);
var right=s.substr(p+s1.length);
return left+s2+right;
}
//////////////////////////////////////
//генерирует строку из пробелов указанной длины
function generateSpaces(len){
var s1="";
for(var i=0; i<len; i++){
s1+=" ";
}
return s1;
}
//////////////////////////////////////
//Извлекает текстовое значение внутри [[викификации]], заменяя все лишнее на пробелы
function spaceWikify(s){
if (s.indexOf("|")>=0){
//если найдена конструкция [[ |
var flagSpace=1; //признак замены на пробел
var s1="";
for(var i=0; i<s.length; i++){
var c=s.charAt(i);
if(c=="|"){
flagSpace=0;
c=" ";
}
if(flagSpace==1){
c=" ";
}
s1+=c;
}
s=s1;
}
s=s.replace(/\[\[/, " "); //[[ на два пробела
s=s.replace(/\]\]/, ""); //[[ на пустую строку, т.к. надо отработать еще слова наподобие [[год]]у
s=s+" ";//добавляем два пробела в конец, чтобы скомпенсировать длину
return s;
}
//////////////////////////////////////
//Подготавливает текст
function prepareText(s, delQuoutes){
//Заменяем знаки препинания на пробелы
s=s.replace(/[\.\,\;\?\!\(\)\—\-\:\=\*]/g, " ");
//Заменим викификацию
var arr=s.match(/\[\[.*?\]\]([^\s])*/g);
if(arr){
for(var i=0; i<arr.length; i++){
var w=arr[i];
var w1=spaceWikify(w); //см. ниже
if(w.length!=w1.length) alert('Строки не совпадают по длине: '+w+'<>'+w1);
s=replace(s, w, w1);
}
}
//Убираем закавыченное, если передан такой параметр
if(delQuoutes){
var arr=s.match(/«.*?»/g);
if(arr){
for(var i=0; i<arr.length; i++){
var w=arr[i];
var w1=generateSpaces(w.length); //см. ниже
s=replace(s, w, w1);
}
}
}
//Убираем то что внутри [квадратных скобок]
var arr=s.match(/\[.*?\]/g);
if(arr){
for(var i=0; i<arr.length; i++){
var w=arr[i];
var w1=generateSpaces(w.length); //см. ниже
s=replace(s, w, w1);
}
}
//Убираем символы кавычек и апострофов
s=s.replace(/[«»„“\"\']/g, " ");
//Убираем {{шаблоны}} Википедии
var arr=s.match(/\{\{.*?\}\}/g);
if(arr){
for(var i=0; i<arr.length; i++){
var w=arr[i];
var w1=generateSpaces(w.length); //см. ниже
s=replace(s, w, w1);
}
}
//Переводим строку в нижний регистр
s=s.toLocaleLowerCase();
//Заменяем ё для целей сравнения
s=s.replace(/ё/g, "е");
//Заменяем различные пробельные символы на пробел
s=s.replace(/\s/g, " ");
return s
}
//////////////////////////////////////
//Измеряет длину совпадения в символах для строк XRomix_s1 и XRomix_s2 начиная с указанных позиций p1 и p2
function checkCompareLength(p1, p2){
var c1=XRomix_s1.charAt(p1);
var c2=XRomix_s2.charAt(p2);
if(c1!=c2){
XRomix_len1=0; //
XRomix_len2=0;
return false;
}
var len1=XRomix_s1.length;
var len2=XRomix_s2.length;
var p1_=p1; //сохраняем позиции для вычисления длины
var p2_=p2;
var p1_nosp=-1; //позиция последнего совпадающего непробельного символа
var p2_nosp=-1;
for(;;){
if(p1>=len1) break;
if(p2>=len2) break;
c1=XRomix_s1.charAt(p1);
c2=XRomix_s2.charAt(p2);
if((c1==" ") && (c2==" ")){
//отыскиваем первый непробельный символ для p1
while(c1==" "){
p1++;
c1=XRomix_s1.charAt(p1);
if(p1>=len1) break;
}
//отыскиваем первый непробельный символ для p2
while(c2==" "){
p2++;
c2=XRomix_s2.charAt(p2);
if(p2>=len2) break;
}
}
//Пропускаем мягкий перенос с кодом 173 (дес) или 0xAD
if(c1=="\xAD"){
p1++;
continue;
}
if(c2=="\xAD"){
p2++;
continue;
}
//Пропускаем символ ударения
if(c1=="́"){
p1++;
continue;
}
if(c2=="́"){
p2++;
continue;
}
if(c1==c2){
if(c1!=" ") p1_nosp=p1;
if(c2!=" ") p2_nosp=p2;
p1++;
p2++;
continue;
}
break;
}
if(p1_nosp==-1){ //не совпал ни один символ
XRomix_len1=0; //
XRomix_len2=0;
}else{
XRomix_len1=p1_nosp-p1_+1; //
XRomix_len2=p2_nosp-p2_+1;
}
return true;
}
////////////////////////////////////////////////////////////////////////////
//Отыскивает максимально совпадающий текст между XRomix_s1 и XRomix_s2
//Помещет его начальные указатели в XRomix_maxP1 и XRomix_maxP1, и длины в XRomix_max1 и XRomix_max1
function getMaxSameText(){
XRomix_maxP1=0;
XRomix_maxP2=0;
XRomix_max1=0;
XRomix_max2=0;
var arr1 = new Array(); //массивы позиций начала слова для ускорения поиска
var arr2 = new Array();
//Заполняем массив позициями начала слова
var c=" ";
var wasSp=1; //признак наличия пробела до текущего символа
for(var i=0; i<XRomix_s1.length; i++){
c=XRomix_s1.charAt(i);
if(c<=" "){
wasSp=1;
continue;
}else{
if(wasSp==0) continue; //пропускаем не первые буквы каждого слова
wasSp=0;
arr1.push(i);
}
}
//Для второй строки делаем то же самое
var wasSp=1; //признак наличия пробела до текущего символа
for(var i=0; i<XRomix_s2.length; i++){
c=XRomix_s2.charAt(i);
if(c<=" "){
wasSp=1;
continue;
}else{
if(wasSp==0) continue; //пропускаем не первые буквы каждого слова
wasSp=0;
arr2.push(i);
}
}
for(var i=0; i<arr1.length; i++){
var p1=arr1[i];
for(var j=0; j<arr2.length; j++){
var p2=arr2[j];
if(checkCompareLength(p1, p2)){
if (XRomix_len2>XRomix_max2){ //сравниваем по второму тексту, т.к. там нет викификации
XRomix_max1=XRomix_len1;
XRomix_max2=XRomix_len2;
XRomix_maxP1=p1;
XRomix_maxP2=p2;
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
function selectInTextArea(txtarea, text1){
//Обрезаем многострочный текст до одной строки - иначе поиск не срабатывает
var arr=text1.split(/[\n\r]/);
var max="";
//найдем максимальную по длине строку из многострочного фрагмента
for(var i=0; i<arr.length; i++){
if (max.length<arr[i].length){ max=arr[i]}
}
text=max;
if (txtarea.setSelectionRange) {//Mozilla/Opera
var selPos = txtarea.value.indexOf(text)
if (selPos < 0) return
txtarea.focus()
txtarea.setSelectionRange(0, 0);//перейдем в начало
//http://www.dynamicdrive.com/dynamicindex11/findpage.htm
var caseSensitive = true // is search case sensitive?
var backwards = false //should we also search backwards?
var wrapAround = true // should we wrap the search?
try{
self.find(text, caseSensitive, backwards, wrapAround);
}catch(e){
}
}else if (txtarea.createTextRange){ //IE
var oRange = txtarea.createTextRange()
if (oRange.findText(text)) oRange.select()
}
}
//подсчитывает концы строк в фрагменте текста
function countCrlf(str){
var cnt=0;
for(var i=0; i<str.length; i++){
var c=str.charCodeAt(i);
if (c==13){
cnt++;
}
}
return cnt;
}
//Браузеро-независимый setSelectionRange - изменяет начало и конец
//выделенного фрагмента в поле ввода input
function setSelectionRange(input, start, end) {
if (typeof wpTextbox1.selectionStart != 'undefined'
&& (navigator.productSub > 20031000 || is_safari)) {
//Mozilla/Opera/Safari3
input.setSelectionRange(start, end);
}else if (document.selection && document.selection.createRange) {
//Internet Explorer
var range = input.createTextRange();
range.collapse(true);
range.moveStart("character", start - countCrlf(input.value.substring(0, start)));
range.moveEnd("character", end - start - countCrlf(input.value.substring(start, end)));
range.select();
}
};
}//function
/////////////////////////////////////////////////////////////////////////////
function XRomix_btnCompare2texts_Compare(){
XRomix_Compare2texts_Compare("first");
var wpSummary = document.getElementById('wpSummary')
if(wpSummary){
var temp=wpSummary.value;
temp=temp.replace(/\/\*.*?\*\// , ""); //комментарии
temp=temp.replace(/[\s]*/ , ""); //пробелы
if (temp==""){
var s=wpSummary.value;
s+=" [[User talk:Khanson/compare2texts.js|compare2texts.js]] - поиск совпадений";
if (s.length<200) wpSummary.value=s;
}
}
}
////////////////////////////////////////////////////////////////////////////
function XRomix_btnCompare2texts_CompareNext(){
XRomix_Compare2texts_Compare("next");
}
// </nowiki>