#javascript #algorithm #similarity
Вопрос:
Я пытаюсь сравнить два разных текста, чтобы сохранить похожие последовательности. Однако я изо всех сил пытаюсь придумать, как это сделать. То, что я ищу, — это что-то вроде этого:
Допустим, у нас есть два сообщения:
Text 1: «Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est here.»
Текст 2: «Привет, я ищу курс по изучению программирования. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. За исключением одного случая, я знаю, что я должен здесь записать».
Я хочу получить похожие последовательности в обоих текстах. В данном случае это:
«Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.»
Но есть два правила:
1 — Сходства должны состоять из групп предложений (поэтому они должны составлять по крайней мере одно предложение); все, что не составляет полного предложения, следует игнорировать.
Например, это должно быть сохранено: «Ut enim ad minim veniam, quis nostrud упражнение ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.»
Но не последовательность из трех слов, идущая сразу за ней: «За исключением sint occaecat».
2 — Повседневные выражения следует игнорировать. (например: «Надеюсь скоро получить от вас весточку», «Да благословит вас Бог» и т. Д.)
Как я могу запрограммировать этот алгоритм, есть ли какой-либо способ сделать это?
Ответ №1:
Пожалуйста, используйте этот код.
//You can add more expressions
const everyday_expressions = ["Hello.", "Hope to hear from you soon", "God bless you"];
const text1 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est here.";
const text2 = "Hi, I'm looking for a course to learn programming. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat idk what I'm supposed to write down here.";
const arr_text1 = text1.split(".").map(val=>val.trim() ".");
const arr_text2 = text2.split(".").map(val=>val.trim() ".");
const result = arr_text1.filter(val => (val.length > 1 amp;amp; arr_text2.indexOf(val) > -1) amp;amp; everyday_expressions.indexOf(val) == -1);
console.log(result);
Ответ №2:
Если производительность важна, рассмотрите возможность использования двоичного поиска:
const commonExpressions = [
'hope to hear from you soon',
'god bless you',
'see you tomorrow',
/* ... */
];
commonExpressions.sort(); // or store them sorted
function binarySearch(arr, str) {
let low = 0, high = arr.length - 1;
while (low <= high) {
const mid = Math.floor((low high) / 2);
const c = arr[mid].localeCompare(str);
if (c < 0) low = mid 1;
else if (c > 0) high = mid - 1;
else return true;
}
return false;
}
function findSimilarities(text1, text2) {
const rawSentences1 = text1.split('.').map(s => s.trim());
const sentences1 = rawSentences1
.map(s => s.toLowerCase())
.filter(s => s amp;amp; !binarySearch(commonExpressions, s));
const sentences2 = text2
.split('.')
.map(s => s.trim().toLowerCase())
.filter(s => s amp;amp; !binarySearch(commonExpressions, s));
sentences2.sort();
let result = sentences1.reduce((matches, s, i) => {
if (binarySearch(sentences2, s)) {
matches.push(i);
}
return matches;
}, []).map(i => rawSentences1[i]).join('. ');
return result amp;amp; result '.';
}
let text1 = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est here.`;
let text2 = `Hi, I'm looking for a course to learn programming. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat idk what I'm supposed to write down here.`;
console.log(findSimilarities(text1, text2));
Я предполагаю здесь, что вам нужно сравнение предложений без учета регистра, поэтому я использую toLowerCase()
.
Обратите внимание, что это решение асимметрично, т. е. замена аргументов может привести к другому результату. Причиной может быть следующее:
- Из-за сравнения без учета регистра совпадающие предложения не обязательно должны быть строго равными. В этом случае заглавная буква из первого текста используется в результирующей строке. Это также причина, по которой мы храним предложения из первого текста с оригинальной заглавной
rawSentences1
буквой в. Если бы мы этого не сделали, результирующая строка была бы написана в нижнем регистре. - Соответствующие предложения появляются в результирующей строке в том порядке, в котором они указаны в первом тексте. Они могут иметь другой порядок во втором тексте и все равно считаться совпадающими. Если вместо этого вы хотите получить как можно больше совпадающих предложений, чтобы они появлялись в одном и том же порядке в обоих текстах, вам следует прочитать о самой длинной общей проблеме с подпоследовательностью.