如何使用Javascript在html文件中搜索字符串?

时间:2017-10-18 18:02:19

标签: javascript html html5 dom xmlhttprequest

我有5个html文件,我有一个搜索表单,我想用它来搜索这些html文件中的文本。

<form>
   <input type ='text' />
   <input type ='submit' />
</form>

我知道使用xmlhttprequest来获取文件

var xhr = new XMLHttpRequest();
xhr.open("GET", "file1.html", false);
xhr.send();
var guid = xhr.responseText;

var xhr = new XMLHttpRequest();
xhr.open("GET", "file2.html", false);
xhr.send();
var guid = xhr.responseText;

...

然后搜索这些文件中的文字,但我不知道如何使用javascript搜索文件。

如何使用xmlhttprequest获取文件后搜索文件?或者是否有其他方法可以使用javascript进行搜索?

2 个答案:

答案 0 :(得分:1)

我使用DOMParser确保我们正在做一些&#34; smart&#34;搜索。我们假设您正在寻找有关“#view; viewport&#34;”这个词的文字。您不希望任何包含<meta>标记&#34;视口&#34;的HTML文件作为有效结果返回,是吗?

第一步是将字符串解析为Document实例:

const parseHTMLString = (() => {
  const parser = new DOMParser();
  return str => parser.parseFromString(str, "text/html");
})();

在此处放置一个有效的HTML字符串,您将获得一个与window.document行为相似的文档!这意味着我们可以使用querySelectorinnerText等属性来执行各种很酷的操作。

下一步是定义我们想要搜索的内容。这是一个加入文档标题和正文的示例:

const getSearchStringForDoc = doc => {
  return [ doc.title, doc.body.innerText ]
   .map(str => str.toLowerCase().trim())
   .join(" ");
};

将已解析的文档传递给此函数,并且您将获得一个纯字符串作为回报,其中只包含内容,没有属性,标记名称和元数据。

现在,问题在于定义正确的搜索方法。可以是基于RegExp的匹配,也可以是(不太快)split&amp; includes

const stringMatchesQuery = (str, query) => {
  return query
    .toLowerCase()
    .split(/\W+/)
    .some(q => str.includes(q))
};

将这些方法链接在一起,你得到了如下转换:

String -> Document -> String -> Boolean

如果您想在搜索内容中包含更多信息,只需使用标准化API更新getSearchStringForDoc功能。

一个正在运行的例子(这有点混乱,可以做一些重构,但希望得到重点):

&#13;
&#13;
const htmlString =  (
`<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>The title</title>
</head>
<body>
  Some text about an interesting thing.
</body>
</html>`);

const parseHTMLString = (() => {
  const parser = new DOMParser();
  return str => parser.parseFromString(str, "text/html");
})();

const getSearchStringForDoc = doc => {
  return [
    doc.title,
    doc.body.innerText
  ].map(str => str.trim())
   .join(" ");
};

const stringMatchesQuery = (str, query) => {
  str = str.toLowerCase();
  query = query.toLowerCase();
  
  return query
    .split(/\W+/)
    .some(q => str.includes(q))
};

const htmlStringMatchesQuery = (str, query) => {
  const htmlDoc = parseHTMLString(str);
  const htmlSearchString = getSearchStringForDoc(htmlDoc);
  
  return stringMatchesQuery(htmlSearchString, query);
};

console.log("Match 'viewport':", htmlStringMatchesQuery(htmlString, "viewport"));
console.log("Match 'Interesting':", htmlStringMatchesQuery(htmlString, "Interesting"));
&#13;
&#13;
&#13;

答案 1 :(得分:0)

首先,改变:

<input type ='text' />

要:

<input id= 'text' type='text' />

然后,下面的代码将创建一个由对象组成的名为“files”的数组。每个对象的'position'属性将包含'filename'中'text'的位置,如果找不到文本则包含-1,如果文件未加载则包含-2。

var text = document.getElementById('text' )

loadCount = 0;
files = [];
files[ 0 ] = {};
files[ 0 ][ 'filename' ] = "file1.html";
files[ 1 ] = {};
files[ 1 ][ 'filename' ] = "file2.html";
files[ 2 ] = {};
files[ 2 ][ 'filename' ] = "file3.html";
files[ 3 ] = {};
files[ 3 ][ 'filename' ] = "file4.html";
files[ 4 ] = {};
files[ 4 ][ 'filename' ] = "file5.html";

function search( item, index ) {

  xmlhttp.onload = function () {
    var files[ index ][ 'contents' ]  = xhr.responseText;
    if ( typeof files[ index ][ 'contents' ] !== 'undefined' ) {
      files[ index ][ 'position' ] = str.indexOf( text );
    } else {
      files[ index ][ 'position' ] = -2;
    }
    loadCount = loadCount + 1;
    if ( loadCount == 5 ) {
      // do whatever you want here
    }
  }

  var xhr = new XMLHttpRequest();
  xhr.open( "GET", item[ 'filename' ], false );
  xhr.send();

}

files.forEach( search );