【问题标题】:Regex - how to find a word not enclosed by html tags or between them正则表达式 - 如何查找未包含在 html 标签或它们之间的单词
【发布时间】:2011-06-12 15:17:15
【问题描述】:

我想在 html 字符串中找到匹配项。

这不会在 html 标记之间或内部。

例如:

单词是:ue

<span color=blue>ue</span>ue<span>sdfsd</span>

所以我只想找到第三个匹配项(不在“蓝色”内),而不是在 span 标记之间。

谢谢

【问题讨论】:

  • 您正在尝试使用正则表达式来解析 HTML。 HTML 不能单独使用正则表达式轻松、可靠地处理。
  • 这是一个字符串:"ueuesdfsd"
  • 这不能仅靠正则表达式可靠地完成。尝试先将文本转换为 DOM 节点。

标签: javascript html regex tags


【解决方案1】:

假设您正在处理 HTML 的片段(而不是完整的文档),您可以编写一个正则表达式来匹配大多数格式良好的最里面的非嵌套元素,然后递归地应用这个正则表达式来删除所有标记的材料,在标签之间留下所需的未标记材料。这是一个匹配大多数空和非空、非嵌套、非短标签 HTML 元素的正则表达式(在注释的 PHP/PCRE 'x' 语法中)。

$re_html = '%# Match non-nested, non-shorttag HTML empty and non-empty elements.
    <                    # Opening tag opening "<" delimiter.
    (\w+)\b              # $1: Tag name.
    (?:                  # Non-capture group for optional attribute(s).
      \s+                # Attributes must be separated by whitespace.
      [\w\-.:]+          # Attribute name is required for attr=value pair.
      (?:                # Non-capture group for optional attribute value.
        \s*=\s*          # Name and value separated by "=" and optional ws.
        (?:              # Non-capture group for attrib value alternatives.
          "[^"]*"        # Double quoted string.
        | \'[^\']*\'     # Single quoted string.
        | [\w\-.:]+\b    # Non-quoted attrib value can be A-Z0-9-._:
        )                # End of attribute value alternatives.
      )?                 # Attribute value is optional.
    )*                   # Allow zero or more attribute=value pairs
    \s*                  # Whitespace is allowed before closing delimiter.
    (?:                  # This element is either empty or has close tag.
      />                 # Is either an empty tag having no contents,
    | >                  # or has both opening and closing tags.
      (                  # $2: Tag contents.
        [^<]*            # Everything up to next tag. (normal*)
        (?:              # We found a tag (open or close).
          (?!</?\1\b) <  # Not us? Match the "<". (special)
          [^<]*          # More of everything up to next tag. (normal*)
        )*               # Unroll-the-loop. (special normal*)*
      )                  # End $2. Tag contents.
      </\1\s*>           # Closing tag.
    )
    %x';

这是 Javascript 语法中相同的正则表达式:

var re_html = /<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[\w\-.:]+\b))?)*\s*(?:\/>|>([^<]*(?:(?!<\/?\1\b)<[^<]*)*)<\/\1\s*>)/;

以下 javascript 函数去除 HTML 元素,在标签之间留下所需的文本:

// Strip HTML elements.
function strip_html_elements(text) {
    // Match non-nested, non-shorttag HTML empty and non-empty elements.
    var re = /<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[\w\-.:]+\b))?)*\s*(?:\/>|>([^<]*(?:(?!<\/?\1\b)<[^<]*)*)<\/\1\s*>)/g;
    // Loop removing innermost HTML elements from inside out.
    while (text.search(re) !== -1) {
        text = text.replace(re, '');
    }
    return text;
}

这个正则表达式解决方案不是一个合适的解析器,只处理只有 html 元素的简单 HTML 片段。它不能(也不能)正确处理具有诸如 cmets、CDATA 部分和 doctype 语句之类的更复杂的标记。它不会删除缺少可选关闭标签的元素(即&lt;p&gt;&lt;li&gt; 元素。)

【讨论】:

    【解决方案2】:

    您正在尝试使用正则表达式来解析 HTML。 HTML 不能单独使用正则表达式轻松、可靠地处理。

    如果您在浏览器上执行此操作,则可以利用浏览器高度优化的 HTML 解析器。

    如果您想在中间有标签时检测单词(例如,“u


    e”):
    var element, node, topLevelText;
    element = document.createElement('div');
    element.innerHTML = "<span color=blue>ue</span>ue<span>sdfsd</span>";
    topLevelText = "";
    for (node = element.firstChild; node; node = node.nextSibling) {
        if (node.nodeType === 3) { // 3 = text node
            topLevelText += node.nodeValue;
        }
    }
    if (topLevelText.indexOf(word) >= 0) {
        // Found
    }
    

    如果你只想在事物之间检测它(所以,你的例子而不是“u


    e”):
    var element, node;
    element = document.createElement('div');
    element.innerHTML = "<span color=blue>ue</span>ue<span>sdfsd</span>";
    for (node = element.firstChild; node; node = node.nextSibling) {
        if (node.nodeType === 3) { // 3 = text node
            if (node.nodeValue.indexOf(word) >= 0) {
                // Found
            }
        }
    }
    

    (两者都进行区分大小写的匹配。)

    这样做

    1. 使用document.createElement 创建一个不在任何地方显示的元素。
    2. 通过将 HTML 文本分配给元素上的 innerHTML 来解析它。这个属性最近才被标准化,但它被所有主流浏览器支持了十年左右。
    3. 查看节点的直接子节点,其中包括通过解析创建的任何元素,以及字符串中顶级文本的文本节点(例如,您要搜索的位置的文本)。这是使用 Node#firstChildNode#nodeTypeNode#nodeValueNode#nextSibling
    4. 根据您是否要在“u
      e”情况下找到它,它要么直接查看每个文本节点中的文本,要么将它们全部构建成一个字符串并随后进行搜索。

    以上链接大多指向DOM2 Core spec,大部分浏览器都支持。其他方便的参考资料:

    【讨论】:

      【解决方案3】:

      HTML 不是regular language,因此无法被regular expressions 解析。

      【讨论】:

      • 我将它作为 javascript 中的字符串获取,并想为其使用正则表达式,但我找不到最好的正则表达式
      • @Itzik984 你不明白人们在告诉你什么 - 包含 HTML 标记的字符串不能用正则表达式可靠地解析。
      • @Itzik984:我需要从亚洲到美洲,我想用一辆车,但我找不到最好的车。
      • @Felix:上述问题没有解决方案。
      【解决方案4】:

      由于您在浏览器中具有出色的 DOM 操作可能性,因此您可以利用它。您可以创建一个新元素,将字符串设置为内容并遍历所有文本节点:

      var tmp = document.createElement('div');
      tmp.innerHTML = htmlString;
      
      var matches = [],
          children = tmp.childNodes,
          node,
          word = ' ' + word + ' ';
      
      for(var i = children.length; i--; ) {
          node = children[i];
          if(node.nodeType === 3 && (' ' + node.nodeValue + ' ').indexOf(word) > -1) {
              matches.push(node);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-12-09
        • 1970-01-01
        • 2014-04-10
        • 2016-12-07
        • 2019-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多