как выделять последовательности искомых подстрок?
Подскажите, как выделять последовательности искомых подстрок?
Исходная строка: <br><input type="text" id="text" placeholder="Введите текст..."><br/><br/> Искомые совпадения: <br><input type="text" name="search" id="search" placeholder="Введите текст..."> <p id="result"></p>
search.oninput = function() {
//подскажите, как это можно сделать
}
|
поиск последовательности слов
Adrikks,
при условии отсутствия служебных символов, иначе нужно добавить экранирование.
<!DOCTYPE html>
<html>
<head>
<title>Untitled</title>
<meta charset="utf-8">
<style type="text/css">
label{
display: flex;
flex-direction: column;
}
#result b{
color: #FF0000;
}
</style>
</head>
<body>
<label>Исходная строка: <input type="text" id="text" placeholder="Введите текст..." value="ЗАКИРОВ АМИРЗЯН ГАЗИЗЬЯНОВИЧ"></label>
<label>Искомые совпадения: <input type="text" name="search" id="search" placeholder="Введите текст..." value="з а г"></label>
<p id="result"></p>
<script>
search.addEventListener('input', _=>{
let txt = text.value, patern = search.value.trim();
if(txt && patern) {
let ar = patern.split(/\s+/);
let reg = ar.map(_=> `(^|\\s+)(${_})(\\S*)`);
patern = new RegExp(reg.join(''), 'i');
txt = txt.replace(patern, a => ar.reduce((a,_, i) => {
patern = new RegExp(reg[i], 'i');
return a.replace(patern, '$1<b>$2</b>$3')
}, a)
)
};
result.innerHTML = txt;
})
//для теста
let event = new Event("input");
search.dispatchEvent(event);
</script>
</body>
</html>
|
рони,
а как совместить, чтобы не только с начала строки искались последовательности, а допустим в исходной строке будет "спасибо" и при искомой "си" выделило бы их в результирующей строчке? |
Цитата:
Цитата:
примеры что на входе, что на выходе. |
рони,
Понимаю. Попробую уточнить. |
Adrikks,
пишите текстом, а не картинкой. :) |
Adrikks,
<!DOCTYPE html>
<html>
<head>
<title>Untitled</title>
<meta charset="utf-8">
<style type="text/css">
label{
display: flex;
flex-direction: column;
}
#result b{
color: #FF0000;
}
</style>
</head>
<body>
<label>Исходная строка: <input type="text" id="text" placeholder="Введите текст..." value="спасибо ЗАКИРОВ АМИРЗЯН ГАЗИЗЬЯНОВИЧ главный врач главный врач"></label>
<label>Искомые совпадения: <input type="text" name="search" id="search" placeholder="Введите текст..." value="си з мир г"></label>
<p id="result"></p>
<script>
search.addEventListener('input', _=>{
let txt = text.value, patern = search.value.trim();
if(txt && patern) {
let ar = patern.split(/\s+/);
let reg = ar.map(_=> `(^\\S*|\\s+\\S*)(${_})(\\S*)`);
patern = new RegExp(reg.join(''), 'ig');
txt = txt.replace(patern, a => ar.reduce((a,_, i) => {
patern = new RegExp(reg[i], 'i');
return a.replace(patern, '$1<b>$2</b>$3')
}, a)
)
};
result.innerHTML = txt;
})
let event = new Event("input");
search.dispatchEvent(event);
</script>
</body>
</html>
|
рони,
Вот не знаю как правильно объяснить, как именно должно работать) Поэтому показываю на примере картинки, каким должен быть результат) |
Adrikks,
пример выше, смотрите. |
рони,
Да, думаю это именно то, что мне нужно было) Спасибо за ваше время :) |
рони, если поискать «с», то находит вторую «с» в слове спасибо. Также всё ломается на специальных символах и в случае, если ввести HTML-код...
Я думаю, что таких проблем можно избежать, экранировав специальные символы в рег. выр.-ний, и вставлять текст на страницу именно как текст!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
label {
display: flex;
flex-direction: column;
}
#result mark {
color: #FF0000;
}
</style>
</head>
<body>
<label>
Исходная строка:
<input id="text" placeholder="Введите текст..." value="спасибо ЗАКИРОВ АМИРЗЯН ГАЗИЗЬЯНОВИЧ главный врач главный врач">
</label>
<label>
Искомые совпадения:
<input id="search" placeholder="Введите текст..." value="си з мир г">
</label>
<p id="result"></p>
<script>
RegExp.escape = s => s.replace(/[[\\^$.|?*+()]/gim, "\\$&");
function mark(string) {
const node = document.createElement("mark");
node.textContent = string;
return node;
}
search.addEventListener("input", () => {
const value = text.value;
const parts = search.value.trim().split(/\s+/);
const pattern = new RegExp(parts.map(RegExp.escape).join("|"), "gi");
let match, index = 0;
result.textContent = "";
if(parts[0].length > 0) while(match = pattern.exec(value))
result.append(
value.slice(index, index = match.index),
mark(value.slice(index, index = pattern.lastIndex))
);
result.append(value.slice(index));
});
search.dispatchEvent(new Event("input"));
</script>
</body>
</html>
|
Malleys,
не вижу преимуществ, не понимаю логики выделения(на мой взгляд в вашем варианте выделяется больше чем нужно), экранизацию предлагал выше, если нужна будет необходимость. и спасибо за превосходный код. <input id="search" placeholder="Введите текст..." value="си з мир г"> <p id="result">спа<mark>си</mark>бо <mark>З</mark>АКИРОВ А<mark>МИР</mark><mark>З</mark>ЯН <mark>Г</mark>А<mark>З</mark>И<mark>З</mark>ЬЯНОВИЧ <mark>г</mark>лавный врач <mark>г</mark>лавный врач</p></body> <p id="result">спа<mark>си</mark>бо <mark>З</mark>АКИРОВ А<mark>МИР</mark>ЗЯН <mark>Г</mark>АЗИЗЬЯНОВИЧ главный врач главный врач</p></body> си з мир г 4 слова последовательно содержащие, 1 слово си, 2 слово з и т.д. если будут ещё 4 слова с таким содержанием в этой же строке, выделить снова так же Цитата:
|
Цитата:
Я показал, как экранировать сп. символы, и как вставить текст на страницу! Цитата:
|
Цитата:
но как расширение перечитал ещё раз, не знаю о чём вы пишите. |
ещё вариант поиска, при условии пробел - слово - пробел ...
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
label {
display: flex;
flex-direction: column;
}
#result mark {
color: #FF0000;
}
</style>
</head>
<body>
<label>
Исходная строка:
<input id="text" placeholder="Введите текст..." value="спасибо ЗАКИРОВ АМИРЗЯН ГАЗИЗЬЯНОВИЧ главный врач главный врач">
</label>
<label>
Искомые совпадения:
<input id="search" placeholder="Введите текст..." value="гл в">
</label>
<p id="result"></p>
<script>
RegExp.escape = s => s.replace(/[[\\^$.|?*+()]/gim, "\\$&");
search.addEventListener("input", () => {
const value = text.value.trim().split(/\s+/);
const parts = search.value.trim().split(/\s+/).map(s => s.toLowerCase());
const length = parts.length;
for (let i = 0; i <= value.length - length; i++) {
let found = value.slice(i, i + length).every((txt, k) => txt.toLowerCase().includes(parts[k]));
if(found) {
parts.forEach((pattern, k) => value[k + i] = value[k + i].replace(new RegExp(RegExp.escape(pattern), "i"), "<mark>$&</mark>"));
i += length - 1;
}
}
result.innerHTML = value.join(" ");
});
search.dispatchEvent(new Event("input"));
</script>
</body>
</html>
|
Цитата:
Например, возьмите в качестве исходного текста такой — Код:
ГАЗИЗЬЯНОВИЧ рулит — главный врач Метки: <врач>, <the-best>Код:
А вы знали, что элемент <mark> используется для подсветки найденного текста?Код:
<div style="position:fixed;top:0;left:0;width:100%;height:100%;background:white;">Dicks, Pussies and Assholes</div> |
Malleys,
ок подумаю. |
Malleys,
может есть иной способ, пока так
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
label {
display: flex;
flex-direction: column;
}
#result mark {
color: #FF0000;
}
</style>
</head>
<body>
<label>
Исходная строка:
<input id="text" placeholder="Введите текст..." value="А вы знали, что элемент <mark> используется для подсветки найденного текста?">
</label>
<label>
Искомые совпадения:
<input id="search" placeholder="Введите текст..." value="п нн кс">
</label>
<p id="result"></p>
<script>
RegExp.escape = s => s.replace(/[[\\^$.|?*+()]/gim, "\\$&");
function mark(string) {
const node = document.createElement("mark");
node.textContent = string;
return node;
}
search.addEventListener("input", () => {
const value = text.value.trim().split(/\s+/);
const parts = search.value.trim().split(/\s+/).map(s => s.toLowerCase());
const length = parts.length;
result.textContent = "";
for (let i = 0; i < value.length; i++) {
let found = value.slice(i, i + length).every((txt, k) => txt.toLowerCase().includes(parts[k]));
if(found) {
parts.forEach((pattern, k) => value[k + i].replace(new RegExp("(\\S*?)(" +RegExp.escape(pattern) +")(\\S*)", "i"), (a,b,c,d) => result.append(
b,
mark(c),
d,
" "
)));
i += length - 1;
}
else result.append(value[i], " ")
}
});
search.dispatchEvent(new Event("input"));
</script>
</body>
</html>
Цитата:
|
рони,
можете подсказать, вот в вашем решении как сделать при этом , чтобы выделялись последовательности и через слова Наверное, другими словами, выделять последовательности во всем тексте Пример: ![]() в этой ситуации должны выделиться и ГЛавный сан ВРач |
Adrikks,
а нельзя без картинок? скопируйте строки и выделите нужные совпадения исходная строка главный врач 12345 главный врач искомые совпадения гл вр главный врач 12345 главный врач :-? |
рони,
ахах, хорошо, не буду больше присылать картинки, раз Вам это не нравится) Думал так понятнее для отображения ожидаемого результата) Пример: исходная строка главный врач 12345 главный сан врач искомые совпадения гл вр главный врач 12345 главный сан врач Вот пример с картинки) Такое не сработает на данный момент если добавить слово между "главный" и "врач" |
Adrikks,
картинка это замечательно пусть будет, но для проверки необходим текст. |
рони,
Понял) В общем суть в том, что должны выделяться последовательности искомых подстрок вне зависимости от кол-ва символов между ними Был бы очень благодарен, если бы подсказали как это можно сделать |
Adrikks,
нужен алгоритм. :) пока не знаю короткой дороги. |
поиск совпадений в последовательности слов
Adrikks,
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
label {
display: flex;
flex-direction: column;
}
#result mark {
color: #FF0000;
}
</style>
</head>
<body>
<label>
Исходная строка:
<input id="text" placeholder="Введите текст..." value="главный врач 12345 главный сан врач">
</label>
<label>
Искомые совпадения:
<input id="search" placeholder="Введите текст..." value="гл вр">
</label>
<p id="result"></p>
<script>
RegExp.escape = s => s.replace(/[[\\^$.|?*+()]/gim, "\\$&");
function mark(string) {
const node = document.createElement("mark");
node.textContent = string;
return node;
}
search.addEventListener("input", () => {
const value = text.value.match(/\s+|\S+/g);
let parts = search.value.trim();
const length = parts.length;
if(!value || !length) {result.textContent = text.value; return};
parts = parts.split(/\s+/).map(pattern => new RegExp("(\\S*?)(" +RegExp.escape(pattern) +")(\\S*)", "i"));
result.textContent = "";
let temp = [];
for (let i = 0; i < value.length; ) {
let k = i, arrFindIndex = [];
let found = parts.every(reg => {
let index = value.slice(k).findIndex(el => reg.test(el));
if(index === -1 ) return false;
k += index;
arrFindIndex.push({k,reg});
k++;
return true
});
if(found) {i = k; temp.push(...arrFindIndex)}
else i++;
}
value.forEach((el, i) => {
const find = temp.find(({k}) => k == i);
if(find){
const {reg} = find;
[_, ...el]= el.match(reg);
el[1] = mark(el[1])
result.append(
...el
)
}
else result.append(el)
})
});
search.dispatchEvent(new Event("input"));
</script>
</body>
</html>
|
рони,
последовательность из двух символов находится везде, а из одного допустим, только один раз Пример как должно: Исходный текст: АЛИЕВА БАЙНАТ АБДУРАХМАНОВНА Искомые совпадения: а б Результат: АЛИЕВА БАЙНАТ АБДУРАХМАНОВНА |
Цитата:
|
рони,
Я понимаю) Я не знаю как вам объяснить всё это в одном алгоритме По этому и кидал картинку |
Adrikks,
Цитата:
должно быть так <p id="result"><mark>А</mark>ЛИЕВА <mark>Б</mark><mark>А</mark>ЙНАТ А<mark>Б</mark>ДУРАХМАНОВНА</p> |
рони,
Я вам показал, как по заданному мне заданию) Ну хотя бы с вариантом представленным у вас, помогите пожалуйста) Больше не побеспокою Вас |
Adrikks,
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
label {
display: flex;
flex-direction: column;
}
#result mark {
color: #FF0000;
}
</style>
</head>
<body>
<label>
Исходная строка:
<input id="text" placeholder="Введите текст..." value="АЛИЕВА БАЙНАТ АБДУРАХМАНОВНА">
</label>
<label>
Искомые совпадения:
<input id="search" placeholder="Введите текст..." value="а б">
</label>
<p id="result"></p>
<script>
RegExp.escape = s => s.replace(/[[\\^$.|?*+()]/gim, "\\$&");
function mark(string) {
const node = document.createElement("mark");
node.textContent = string;
return node;
}
search.addEventListener("input", () => {
const value = text.value;
let parts = search.value.trim();
const length = parts.length;
if(!value || !length) {result.textContent = text.value; return};
parts = parts.split(/\s+/).map(pattern => new RegExp("(" +RegExp.escape(pattern) +")", "i"));
result.textContent = "";
let temp = [];
for (let i = 0; i < value.length; ) {
let k = i, arrFindIndex = [];
let found = parts.every(reg => {
reg.lastIndex = 0;
let match = reg.exec(value.slice(k));
if(match) {
k += match.index
arrFindIndex.push(k, k += match[0].length);
return true
}
return false;
});
if(found) {i = k; temp.push(...arrFindIndex)}
else i++;
}
let index = 0;
for (let i = 0; i < temp.length; i += 2){
result.append(
value.slice(index, index = temp[i]),
mark(value.slice(index, index = temp[i + 1]))
);
}
result.append(value.slice(index));
});
search.dispatchEvent(new Event("input"));
</script>
</body>
</html>
|
рони,
спасибо большое за помощь и за терпение. |
рони,
решаю подобную задачу. Можете объяснить, что вы делаете здесь? RegExp.escape = s => s.replace(/[[\\^$.|?*+()]/gim, "\\$&"); и здесь
let found = parts.every(reg => {
reg.lastIndex = 0;
let match = reg.exec(value.slice(k));
if(match) {
k += match.index
arrFindIndex.push(k, k += match[0].length);
return true
}
return false;
});
if(found) {i = k; temp.push(...arrFindIndex)}
else i++;
}
let index = 0;
for (let i = 0; i < temp.length; i += 2){
result.append(
value.slice(index, index = temp[i]),
mark(value.slice(index, index = temp[i + 1]))
);
}
result.append(value.slice(index));
(комментарии возможно), если не трудно. Относительно недавно начала изучать JavaScript. |
JoenRules,
RegExp.escape экранирование служебных символов https://learn.javascript.ru/regexp-escaping . это любой символ в RegExp \. это просто точка если в строке поиска есть точка, нужно "уточнить" (экранировать) что это именно точка. подробнее по ссылке.
let found = parts.every(reg => { // parts -> массив всех совпадений
// every -> каждое совпадение должно быть в проверяемой строке
reg.lastIndex = 0; //искать с начала строки
let match = reg.exec(value.slice(k));//проверка совпадения
if(match) {//если совпадение есть
k += match.index
arrFindIndex.push(k, k += match[0].length); //запоминаем совпадение с такого символа по такой
return true // продолжаем поиск
}
return false;// прекращаем поиск если хотябы одного совпадения нет
});
if(found) {i = k; temp.push(...arrFindIndex)} //если поиск был удачный сокращаем строку на длину совпадений
// и сохраняем все сопадения
else i++; //иначе сокращаем строку на один символ
// продолжаем поиск по строке пока есть длина строки
}
let index = 0;//вывод результата с начала строки
for (let i = 0; i < temp.length; i += 2){// цикл по участкам совпадения
result.append(
value.slice(index, index = temp[i]), // вывод строки до совпадения
mark(value.slice(index, index = temp[i + 1]))// вывод элемента mark с текстом совпадения
);
}
result.append(value.slice(index)); //вывод последнего участка строки
|
| Часовой пояс GMT +3, время: 22:45. |