检查一个字符串是否为HTML格式

147

我有一个字符串,想要检查它是否为HTML格式。我使用正则表达式进行匹配,但是结果不正确。

我验证了我的正则表达式,在这里是有效的。

var htmlRegex = new RegExp("<([A-Za-z][A-Za-z0-9]*)\b[^>]*>(.*?)</\1>");
return htmlRegex.test(testString);

这是 jsfiddle 的链接,但正则表达式在那里没有运行。http://jsfiddle.net/wFWtc/

在我的电脑上,代码能够正常运行,但结果为 false 而不是 true。 我错过了什么?


7
使用 HTML 解析器解析 HTML。如果您还没有阅读过,请阅读此链接(https://dev59.com/X3I-5IYBdhLWcg3wq6do#1732454)。 - Frédéric Hamidi
3
问题不断出现,应该有一个堆栈机器人,可以自动为每个包含 HTML 和正则表达式的问题设置评论。 - Bartlomiej Lewandowski
3
这有点取决于你想要检查的复杂程度。你可以检查字符串中是否包含至少一个<和至少一个>,并将其称为HTML,或者你可以检查它是否具有正确的HTML语法,并严格有效,也可以在两者之间任意选择。对于最简单的情况,不需要使用HTML解析器。 - JJJ
3
为什么要检查一个字符串是否为HTML? - nhahtdh
2
@user1240679:有效的标记格式?什么样的有效性?严格来说,您需要DTD来描述它。在宽松的意义上,您可能希望检查标记是否正确匹配。以上两种情况都不适合使用正则表达式。 - nhahtdh
显示剩余4条评论
20个回答

3
在这种情况下,使用jQuery的最简单形式如下所示:
if ($(testString).length > 0)

如果 $(testString).length = 1,这意味着 textStging 中只有一个 HTML 标签。

1
根据下面的答案(从四年前开始,以“使用jQuery”开头),请考虑从单个入口点进行多次使用的不良选择。 $()是CSS选择器操作。 但也是文本HTML序列化的DOM节点工厂。 但是...根据另一个答案所遭受的与jQuery相同的依赖,“div”不是HTML,但如果页面上存在任何<div>元素,则会返回true。 这是一种非常糟糕的方法,我已经习惯了几乎所有不必要地涉及jQuery的解决方案。(让它死去吧。) - amcgregor

1
使用以下函数作为工具来检查最佳方法:
const containsHTML = (str: string) => /<[a-z][\s\S]*>/i.test(str);

1

原始请求并没有说解决方案必须是一个RegExp,只是尝试使用RegExp。我会提供这个解决方案。如果可以解析单个子元素,则说明它是HTML。请注意,如果body仅包含注释、CDATA或服务器指令,则此方法将返回false。

const isHTML = (text) => {
  try {
    const fragment = new DOMParser().parseFromString(text,"text/html");
    return fragment.body.children.length>0
  } catch(error) { ; }  
  return false;
}

1

有一些花哨的解决方案,涉及利用浏览器本身来尝试解析文本,识别是否构建了任何DOM节点,这将会……很慢。或者使用正则表达式,速度会更快,但是……可能不准确。此问题还有两个非常不同的问题:

Q1:一个字符串包含HTML片段吗?

字符串部分是HTML文档,包含HTML元素标记或编码实体吗?这可以用作指示器,表明该字符串可能需要漂白/清理或实体解码:

/</?[a-z][^>]*>|(\&(?:[\w\d]+|#\d+|#x[a-f\d]+);/

在本文撰写时,您可以在所有现有答案的示例中看到此模式的使用情况,还包括一些相当丑陋的所见即所得或 Word 生成的示例文本以及各种字符实体引用。

问题2:该字符串是否为 HTML 文档?

HTML 规范对于它认为的 HTML 文档非常宽松。 浏览器会尽最大努力将几乎任何垃圾文本解析为 HTML。有两种方法:要么将所有内容都视为 HTML(因为如果使用 text/html Content-Type 提供,则用户代理将花费很大的精力来尝试将其解释为 HTML),要么查找前缀标记:

<!DOCTYPE html>

就“格式正确性”而言,几乎仅此一项是“必需的”。以下是一个完整、有效的 HTML 文档,其中包含您认为被省略的每个 HTML 元素:
<!DOCTYPE html>
<title>Yes, really.</title>
<p>This is everything you need.

是的。有明确的规则来形成“缺失”的元素,例如<html><head><body>。尽管我觉得很有趣的是,SO的语法高亮在没有显式提示的情况下无法正确检测到它们。

0

我需要类似于 XML 字符串的东西。 我会把我想到的放在这里,以防对任何人有用。

static isXMLstring(input: string): boolean {
    const reOpenFull = new RegExp(/^<[^<>\/]+>.*/);
    const reOpen = new RegExp(/^<[^<>\/]+>/);
    const reCloseFull = new RegExp(/(^<\/[^<>\/]+>.*)|(^<[^<>\/]+\/>.*)/);
    const reClose = new RegExp(/(^<\/[^<>\/]+>)|(^<[^<>\/]+\/>)/);
    const reContentFull = new RegExp(/^[^<>\/]+.*/);
    const reContent = new RegExp(/^[^<>&%]+/); // exclude reserved characters in content

    const tagStack: string[] = [];

    const getTag = (s: string, re: RegExp): string => {
      const res = (s.match(re) as string[])[0].replaceAll(/[\/<>]/g, "");
      return res.split(" ")[0];
    };

    const check = (s: string): boolean => {
      const leave = (s: string, re: RegExp): boolean => {
        const sTrimmed = s.replace(re, "");
        if (sTrimmed.length == 0) {
          return tagStack.length == 0;
        } else {
          return check(sTrimmed);
        }
      };

      if (reOpenFull.test(s)) {
        const openTag = getTag(s, reOpen);
        tagStack.push(openTag); // opening tag
        return leave(s, reOpen);
      } else if (reCloseFull.test(s)) {
        const openTag = tagStack.pop();
        const closeTag = getTag(s, reClose);
        if (openTag != closeTag) {
          return false;
        }
        // closing tag
        return leave(s, reClose);
      } else if (reContentFull.test(s)) {
        if (tagStack.length < 1) {
          return false;
        } else {
          return leave(s, reContent); // content
        }
      } else {
        return false;
      }
    };

    return check(input);
  }

0

最受欢迎的答案将以下字符串验证为HTML模式,但实际上它并不是:

true = (b<a || b>=a)

更好的方法是<([a-zA-Z]+)(\s*|>).*(>|\/\1>),可以在这里进行可视化。

有关详细信息,请参见HTML标准

此模式不会验证您的HTML文档,而是验证HTML标记。显然还有改进的空间,您改进得越多,就越快获得非常复杂的HTML验证模式,这是您想避免的。

示例

<t>
<a >
<g/>
<tag />
<tag some='1' attributes=2 foo >...
<tag some attributes/>
<tag some attributes/>...</tagx>

0
这是我在自己的项目中使用的一种无正则表达式方法。
如果您正在尝试在其他非HTML字符串中检测HTML字符串,可以将其转换为HTML解析器对象,然后再转回来,看看字符串长度是否不同。例如:
以下是Python实现示例:
def isHTML(string):
    string1 = string[:]
    soup = BeautifulSoup(string, 'html.parser')  # Can use other HTML parser like etree
    string2 = soup.text

    if string1 != string2:
        return True
    elif string1 == string2:
        return False

它在我的2800个字符串样本上运行成功。

伪代码如下:

define function "IS_HTML"
  input = STRING
  set a copy of STRING as STRING_1
  parse STRING using an HTML parser and set as STRING_2
  IF STRING_1 is equal to STRING_2
  THEN RETURN TRUE
  ELSE IF STRING_1 is not equal to STRING_2
  THEN RETURN FALSE

这在我的测试案例中有效,它可能也适用于你。


我猜你最好在某个地方标注这是Python解决方案(而问题是关于JS的)。 - Nikita Popov

0

我的解决方案是

const element = document.querySelector('.test_element');

const setHtml = elem =>{
    let getElemContent = elem.innerHTML;

    // Clean Up whitespace in the element
    // If you don't want to remove whitespace, then you can skip this line
    let newHtml = getElemContent.replace(/[\n\t ]+/g, " ");

    //RegEX to check HTML
    let checkHtml = /<([A-Za-z][A-Za-z0-9]*)\b[^>]*>(.*?)<\/\1>/.test(getElemContent);

    //Check it is html or not
    if (checkHtml){
        console.log('This is an HTML');
        console.log(newHtml.trim());
    }
    else{
        console.log('This is a TEXT');
        console.log(elem.innerText.trim());
    }
}

setHtml(element);

你的正则表达式似乎存在严重问题,而更全面的表达式需要预处理(初始替换),这是非常不幸的。 - amcgregor

0
你也可以尝试这个简单的解决方案。
window.isHTML=(content)=>{
    let elem = document.createElement('p');
    elem.innerHTML = content;
    return elem.children.length > 0;
}

isHTML('hello') //false
isHTML('<p>hello</p>') //true
isHTML('<p>hello</p> world') //true

-1

我不理解它试图使用的表达式,该表达式除了声明的文档类型之外都会失败,而从附加依赖项中提取的已知HTML元素构成的“完整”模式忽略了HTML的工作方式,而且很长一段时间以来一直如此。此外,基本模式明确提到<html><body>标签,这两个标签都是完全可选的。 "不匹配XML"测试是有意义的。 - amcgregor
@amcgregor 如果您认为您的解决方案更好,也许可以为isHTML存储库做出贡献?并从regex101添加您的测试套件?这将对社区非常有价值。 - Colin D
该库的根本目的是错误的,并且在许多情况下本质上都是错误的,通常会由于存在它不理解的标签而误报为非HTML;这种方式无法实现验证。此外,一个简单的正则表达式或一组库...我们可能已经忘记了如何编程,Node / NPM不是我通常希望使用、贡献或鼓励使用的语言或工具链。 - amcgregor
好的,amcgergor,你对我非常消极,而我只是想帮忙。我不同意 npm 是误导的前提。想象一下,如果你的 stack overflow 答案在未来进行了一些小的调整,作为使用你库的开发者,我只需要升级,就可以得到更合适的行为。相反,我必须……忍受错误的行为或重新查看这个 stack overflow 答案以获取你的编辑?那是另一个宇宙。 - Colin D
负面的?我在解释我的立场以及为什么我不会做一个本来看起来很明智的事情。请注意,我链接的文章是稍微有点激进的第一篇(提前链接),引发了大量讨论。他发表了一篇技术论文,也在那里链接,位于底部。我用关于质量的证据反驳了你对重做工作的直觉。参考:§7.2(以及left-pad灾难和eslint)。 - amcgregor
这与原始问题无关了。不过还是感谢您的观点。 - Colin D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接