Поиск фразы по тексту
Привет всем!
Кто может помочь с теорией (или примером), а то я что то уже запутался в край. Итак, есть простой HTML-код:
<html>
<head>
<title>Test Search</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<script language="javascript">
//возвращает список textnode заданого node
function TNList(node,list){
for(var a=0;a<node.childNodes.length;a++){
if(node.childNodes[a].nodeType==3)
list.push(node.childNodes[a]);
else
TNList(node.childNodes[a],list);
}
}
//поиск и выделение объекта (DOM)
function search_and_select(b,str){
var ltn=new Array();
TNList(b,ltn);
for(var a=0;a<ltn.length;a++){
if(ltn[a].nodeValue.indexOf(str)!=-1){
var s=window.getSelection();
var r=document.createRange();
r.setStart(ltn[a],ltn[a].nodeValue.indexOf(str));
r.setEnd(ltn[a],ltn[a].nodeValue.indexOf(str)+str.length);
s.removeAllRanges();
s.addRange(r);
alert('Found!');
}else{
alert('Not Found');
}
}
}
//инициализация
var init=function(){
var str='text into';
search_and_select(document.body,str);
};
</script>
</head>
<body onload="init();">
<div id="child1">Any text into div <span id="child11">and text into span</span> tags</div>
</body>
</html>
По коду понятно, что при загрузке страницы будет произведён поиск фразы 'text into' по всем textnod'ам рекурсивно, находящихся в body. Всё бы хорошо, если поиск будет производиться только внутри textnod'ов. Но что, если, например, понадобится найти фразу 'div and text', у которой начало начинается в одной textnod'е, а окончание в другой? В теории всё понятно
setStart(document.getElementById('child1').firstChild,14);
setEnd(document.getElementById('child11').firstChild,8);
А вот как это практически реализовать что то никак сообразить не могу. Есть у кого какие мысли по этому поводу? |
может уже поздно, но... можно получить innerText + внешний список DOM-элементов с указанием к какой его части они относятся
|
Нет, не поздно, вопрос ещё открыт и достаточно актуальный.
Однако innerText разве не присущ только для IE? Вопрос с IE не берётся во внимание вообще, потому что я под него написал класс, с помощью которого IE с Range работает по DOM-стандарту. К тому же, у IE есть свойство range.findText. Вообще, мысли очень "хлипкие" по этому поводу. Например, можно создать range всего документа и сузить его до границ body. Далее через selectNodeContents() и toString() вытащить его текстовое содержимое, где производить поиск фразы. Фразу то он находит, а вот как получить граничные точки найденной фразы (startContainer, startOffset, endContainer, endOffset) пока не могу понять. |
ну я не имел в виду буквально innerText, я имел в виду получить текст содержащийся в элементе и всех его детях
т.е. можно создавать этот "innerText" и параллельно создавать другую структуру, в которой отмечать какой элемент в какой позиции "innerText" начинается и где заканчивается. Потому ищем в полученном "innerText" и по внешней структуре находим нужные элементы |
Всё таки решил я эту задачу, но не полностью. Честно говоря, решение мне то же не очень нравится, очень похоже на "подгонку на ответ", но других мыслей пока не появилось.
В данном решении поиск фразы (например, "body Any text") производится по всему тексту и находит все, кроме 2 мест. В коде так же есть часть закоментированноого кода, которая, если её раскомментировать, находит все вхождения, но выделяет найденный текст со смещением. Как это побороть?
<html>
<head>
<title>Search Text</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />
<script language="javascript">
function getTextNodeList(parentNode,list){
for(var a=0;a<parentNode.childNodes.length;a++){
if(parentNode.childNodes[a].nodeType==3){
if(parentNode.childNodes[a].nodeValue.length==1&&parentNode.childNodes[a].nodeValue==="\n")
continue;
else
list.push({
n: parentNode.childNodes[a],
s: list[list.length-1]?parseInt(list[list.length-1].s)+parseInt(list[list.length-1].l):0,
l: parentNode.childNodes[a].length
});
}else{
getTextNodeList(parentNode.childNodes[a],list);
}
}
}
var storage={
srch: '',
lastIdx: -1,
result: new Array(),
clear: function(){
with(storage){
srch='';
lastIdx=-1;
result=new Array();
}
},
search: function(){
if(storage.srch!==''){
var b=document.body;
var list=new Array();
getTextNodeList(b,list);
var r=document.createRange();
r.selectNodeContents(b);
var c='';
var v=null;
for(var a=0;a<list.length;a++){
v=list[a].n.nodeValue;
c+=v.replace(/\n/gim," ");
/*
* Если раскомментировать этот блок, ищет все фразы
* но "со смещением"
if(v.charAt(v.length-1)!==" "&&v.charAt(v.length-1)!=="\n"){
console.log('"'+v+'"');
c+=' ';
}
*/
}
console.log(c);
var p=new RegExp(storage.srch,"ig");
var data=null;
var startContainer=null;
var startOffset=0;
var endContainer=null;
var endOffset=0;
var start=0;
var end=0;
var ls=0;
var ll=0;
while((data=p.exec(c))!=null){
start=p.lastIndex-storage.srch.length;
end=p.lastIndex;
for(var a=0;a<list.length;a++){
ls=parseInt(list[a].s);
ll=ls+parseInt(list[a].l);
if(start>=ls&&start<ll){
startContainer=list[a].n;
startOffset=start-ls;
}
if(end>=ls&&end<ll){
endContainer=list[a].n;
endOffset=end-ls;
}
}
storage.result.push({
sc: startContainer,
so: startOffset,
ec: endContainer,
eo: endOffset
});
}
}
},
init: function(){
storage.clear();
if(arguments[0])
with(storage){
srch=arguments[0];
search();
}
}
};
function findNext(){
var i=document.getElementById('srchText');
if(storage.result.length==0 || (storage.srch!==i.value && i.value!=='')){
storage.init(i.value);
}
if(storage.result.length>0){
var s=null;
var r=null;
// for Gecko only
if(window.getSelection){
var s=window.getSelection();
var r=document.createRange();
storage.lastIdx++;
if(storage.lastIdx>storage.result.length-1)
storage.lastIdx=0;
r.setStart(storage.result[storage.lastIdx].sc,storage.result[storage.lastIdx].so);
r.setEnd(storage.result[storage.lastIdx].ec,storage.result[storage.lastIdx].eo);
s.removeAllRanges();
s.addRange(r);
}
}else{
alert('Совпадений не найдено');
}
}
</script>
</head>
<body>
Any text into body Any text into body
<div>Any text into body Any text into body <span>Any text into body Any text into body <span>Any text into body Any text into body</span></span></div>
<div>Any text into body Any text into body</div>
<span>Any text into body Any text into body</span>
Any text into body Any text into body
<br />
<input id="srchText" type="text" value="" /><input type="button" value="Search" onclick="findNext()" />
</body>
</html>
|
| Часовой пояс GMT +3, время: 07:54. |