改进JavaScript正则表达式以匹配标签内的内容,有或没有结束标记,不包括self

时间:2017-07-31 06:34:07

标签: javascript regex

  

前言:我知道反对使用 regex 解析HTML的普遍共识。提前询问,请避免在这方面提出任何建议。

说明

我有以下正则表达式

/<div class="panel-body">([^]*?)(<\/div>|$)/gi

它匹配div内的所有内容,包括自我,内容为.panel-body

完全匹配:

<div class="panel-body">
   <a href="#">Link</a>
   Line 1
   Line 2
   Line 3
</div>

..它还匹配没有结束div标记的内容。

完全匹配:

<div class="panel-body">
   <a href="#">Link</a>
   Line 1
   Line 2
   Line 3
   Don't match after closing `div`...but match this and below in case closing `div` is removed.
   Line below 1
   Line below 2
   Line below 3

问题。

如何改进我的正则表达式以执行以下操作:

  1. 不包含在完整匹配<div class="panel-body">和结束</div>(当有结束div标记时)

  2. 直接(如果可能)直接进入完全匹配而不使用群组

  3. regex101.com example

    编辑1:

    字符串不以<div class="panel-body">开头,而是以

    开头
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Webmin 1.851 on centos.centos (CentOS Linux 7.3.1611)</title>
    </head>
    <body>
    <div>
    <div>
    <div class="panel-body">
    

    * 注意:它在完全加载之前从不关闭,因为它是渐进式输出。

    编辑2:

    在发布答案后,我进行了速度比较测试。这取决于你,他的解决方案最适合你。

    Speed-test Results

4 个答案:

答案 0 :(得分:3)

您可以使用DOM解析器,该解析器也应包含不完整的标记:

&#13;
&#13;
function divContent(str) {
  // create a new dov container
  var div = document.createElement('div');

  // assign your HTML to div's innerHTML
  div.innerHTML = '<html>' + str + '</html>';

  // find an element by given className
  var el = div.getElementsByClassName("panel-body");
  
  // return found element's first innerHTML
  return (el.length > 0 ? el[el.length-1].innerHTML : "");
}

// extract text from a complete tag:
var html = `<div class="panel-body">
   <a href="#">Link</a>
   Line 1
   Line 2
   Line 3
</div>`;
console.log(divContent(html));

// extract text from an incomplete tag:
html = `<div class="panel-body">
   <a href="#">Link</a>
   Line 1
   Line 2
   Line 3
   Don't match after closing 'div'...but match this and below
   in case closing 'div' is removed.
   Line below 1
   Line below 2
   Line below 3`;   
console.log(divContent(html));

// OP'e edited HTML text
html = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Webmin 1.851 on centos.centos (CentOS Linux 7.3.1611)</title>
</head>
<body>
<div>
<div>
<div class="panel-body">`;
console.log(divContent(html));
&#13;
&#13;
&#13;

JS Fiddle

答案 1 :(得分:2)

我无法评论,所以我会尝试一个答案。如何非捕获组,你仍然在完全匹配,但你唯一的匹配条目将是内容。索引0。

(?:<div class="panel-body">)([^]*?)(?:<\/div>|$)

https://regex101.com/r/OJf1Rt/3

答案 2 :(得分:2)

它必须是正则表达式吗?您可以只查找开始标记,并可选择删除结束标记(如果存在):

function parseContent(input) {
  var openingTag = '<div class="panel-body">';

  var i = input.indexOf(openingTag);
  if (i == -1) {
    return ""; // Or something else
  }

  var closingTag = '</div>';
  var closingTagLength = closingTag.length;
  var end = input.length - (input.slice(-closingTagLength) === closingTag ? closingTagLength : 0);

  return input.slice(i + openingTag.length, end);
}

编辑:

如果结束标记后面有文字,那么也只需使用indexOf

function parseContent(input) {
  var openingTag = '<div class="panel-body">';

  var i = input.indexOf(openingTag);
  if (i == -1) {
    return ""; // Or something else
  }

  var closingTag = '</div>';

  var endIndex = input.indexOf(closingTag, i);
  var end = (endIndex === -1 ? input.length : endIndex);

  return input.slice(i + openingTag.length, end);
}

答案 3 :(得分:1)

如果无标记,您可以使用 - 所有行都不以&lt;开头字符

(^|\r|\n|\r\n)[^<]+

具体示例获取第一行

\<[^div] ([^\r\n]*\n)+

如果您需要将最后一个字符结束后还有其他行:

\<[^div] ([^\r\n]*\n)+Line 3