检查字符串是否为html


98

我有一个特定的字符串,我想检查它是否为html。我使用正则表达式相同,但没有得到正确的结果。

我验证了我的正则表达式,在这里工作正常。

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

这是小提琴,但正则表达式未在其中运行。http://jsfiddle.net/wFWtc/

在我的机器上,代码可以正常运行,但结果为false而不是true。这里缺少什么?


5
使用HTML解析器来解析HTML。如果尚未阅读,请阅读此内容
弗雷德里克·哈米迪

3
问题不断到来,应该有一个堆栈机器人,它将对每个带有html和regex的问题进行无聊的评论
Bartlomiej Lewandowski

3
这有点取决于您要从支票中选择什么级别。您可以检查字符串是否包含至少一个<和至少一个,>并将其称为HTML,或者可以使用正确的HTML语法或介于两者之间的任何内容来检查其是否严格有效。对于最简单的情况,不需要HTML解析器。
JJJ

2
为什么检查字符串是HTML?
nhahtdh

2
@ user1240679:有效的标记格式?什么样的有效性?从最严格的意义上讲,您需要DTD对其进行描述。从广义上讲,您可能需要检查标签是否正确匹配。上述2种情况中的任何一种都不适合正则表达式。
nhahtdh

Answers:


315

用于检查字符串是否为HTML的更好的正则表达式是:

/^/

例如:

/^/.test('') // true
/^/.test('foo bar baz') //true
/^/.test('<p>fizz buzz</p>') //true

事实上,它是那么好,它会返回true每个传递给它的字符串,这是因为每一个字符串是HTML。严重的是,即使格式不正确或无效,它仍然是HTML。

如果您要查找的是HTML元素而不是任何文本内容,则可以使用以下方法:

/<\/?[a-z][\s\S]*>/i.test()

它不会以任何方式帮助您解析HTML,但可以肯定地将字符串标记为包含HTML元素。


47
老实说,我很惊讶我没有得到更多的蛇票。
zzzzBov

7
@clenemt,所以您认为a < b && a > c是HTML?
zzzzBov

1
@zzzzBov,您知道您认为a<b && a>c自己是HTML ...我希望可以将HTML检测大大简化。解析绝非易事。
oriadam '16

2
@oriadam,上下文是在这种情况下用于检测元素的。如果使用a < b && a > c浏览器,则会将><字符适当地转换为&gt;&lt;实体。相反,如果您使用a<b && a>c浏览器,则会将标记解释为标记,a<b && a>c</b>因为缺少空格意味着会<b打开一个<b>元素。这是我在说的简短演示
zzzzBov

4
这可能是我所看到的投票最高的巨魔答案。;)
aandis

72

方法1。这是测试字符串是否包含HTML数据的简单函数:

function isHTML(str) {
  var a = document.createElement('div');
  a.innerHTML = str;

  for (var c = a.childNodes, i = c.length; i--; ) {
    if (c[i].nodeType == 1) return true; 
  }

  return false;
}

这个想法是允许浏览器DOM解析器确定所提供的字符串是否看起来像HTML。如您所见,它只需检查ELEMENT_NODEnodeTypeof 1)。

我进行了一些测试,看起来很有效:

isHTML('<a>this is a string</a>') // true
isHTML('this is a string')        // false
isHTML('this is a <b>string</b>') // true

此解决方案将正确检测HTML字符串,但是它具有img / vide / etc的副作用。一旦在innerHTML中进行了解析,标记将开始下载资源。

方法2。另一种方法使用DOMParser,并且没有加载资源的副作用:

function isHTML(str) {
  var doc = new DOMParser().parseFromString(str, "text/html");
  return Array.from(doc.body.childNodes).some(node => node.nodeType === 1);
}

注意:
1. Array.from是ES2015的方法,可以替换为[].slice.call(doc.body.childNodes)
2. some通话中的箭头功能可以替换为通常的匿名功能。


3
这是一个很棒的主意。但是,此功能无法检测到结束标签(即isHTML("</a>") --> false)。
刘易斯

9
伟大的解决方案!..的唯一负面影响是,如果您的html包含任何静态资源(例如图像src属性),innerHTML将迫使浏览器开始获取这些资源。:(
何塞·布朗

@JoseBrowne即使未附加到DOM?
kuus

1
@kuus是的,即使没有附加。使用DOMParser解决方案。
dfsq

1
好主意,但是被接受的答案会不会对性能更好?特别是如果您有很大的字符串(用于双关语)或必须大量使用此测试。
DerpyNerd,

13

进行以下验证:

/<(?=.*? .*?\/ ?>|br|hr|input|!--|wbr)[a-z]+.*?>|<([a-z]+).*?<\/\1>/i.test(htmlStringHere) 

这将搜索空标签(某些预定义的)并/终止XHTML空标签,并由于空标签而将其验证为HTML,否则将捕获标签名称并尝试在字符串中的某处找到其结束标签以将其验证为HTML。

演示说明:http//regex101.com/r/cX0eP2

更新:

完成验证:

/<(br|basefont|hr|input|source|frame|param|area|meta|!--|col|link|option|base|img|wbr|!DOCTYPE).*?>|<(a|abbr|acronym|address|applet|article|aside|audio|b|bdi|bdo|big|blockquote|body|button|canvas|caption|center|cite|code|colgroup|command|datalist|dd|del|details|dfn|dialog|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frameset|head|header|hgroup|h1|h2|h3|h4|h5|h6|html|i|iframe|ins|kbd|keygen|label|legend|li|map|mark|menu|meter|nav|noframes|noscript|object|ol|optgroup|output|p|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|span|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|track|tt|u|ul|var|video).*?<\/\2>/i.test(htmlStringHere) 

这样做会进行正确的验证,因为它包含所有 HTML标记,首先是空标记,然后是需要关闭标记的其余HTML标记。

在此处解释了演示:http : //regex101.com/r/pE1mT5


1
请注意,底部正则表达式确实有效,但它不会检测到未封闭的html标签,例如“'<strong> hello world”。如果这是损坏的html,则应将其视为字符串,但出于实际目的,您的应用程序可能也希望检测到这些。
TK123

HTML的设计考虑了用户代理的宽恕。“无效”标签不是无效标签,它们只是未知的并且被允许。“无效”属性不是无效的……当人们开始涉及“ Web组件”和诸如JSX之类的技术时,这一点尤其明显。将此文件打成文件并进行评估document.querySelector('strange')-它将起作用。
amcgregor

(总而言之:由于规范的编写方式,尝试“验证” HTML标记本质上是一种愚蠢的做法。给示例HTML文档提供的带有“ invalid”元素的链接是100%完整的格式,完整的HTML文档(并且自1997年以来一直是另一个示例。)
amcgregor

9

上面的zzzzBov的答案是好的,但是它不能说明杂散的关闭标签,例如:

/<[a-z][\s\S]*>/i.test('foo </b> bar'); // false

也可以捕获结束标记的版本可能是这样的:

/<[a-z/][\s\S]*>/i.test('foo </b> bar'); // true

建议最好进行编辑,而不是将其发布为评论。
Zlatin Zlatev

我想你的意思是<[a-z/][\s\S]*>-注意第一组中的斜线。
瑞安·吉尔

7

这是我不时使用的草率单线:

var isHTML = RegExp.prototype.test.bind(/(<([^>]+)>)/i);

基本上将返回true包含<后跟ANYTHING后跟的字符串>

通过 ANYTHING,我的意思是除了空字符串外,基本上什么都没有。

这不是很好,但是它是单线的。

用法

isHTML('Testing');               // false
isHTML('<p>Testing</p>');        // true
isHTML('<img src="hello.jpg">'); // true
isHTML('My < weird > string');   // true (caution!!!)
isHTML('<>');                    // false

如您所见,它远非完美,但在某些情况下可能会为您完成工作。


1
正是我所需要的。没什么好看的,只是干净的。谢谢!
moeiscool

6

这里的所有答案都包含在内,它们只是在寻找,<然后是>。没有完美的方法来检测字符串是否为HTML,但是您可以做得更好。

下面我们将寻找结束标签,它将更加紧密和准确:

import re
re_is_html = re.compile(r"(?:</[^<]+>)|(?:<[^<]+/>)")

它在起作用:

# Correctly identified as not HTML:
print re_is_html.search("Hello, World")
print re_is_html.search("This is less than <, this is greater than >.")
print re_is_html.search(" a < 3 && b > 3")
print re_is_html.search("<<Important Text>>")
print re_is_html.search("<a>")

# Correctly identified as HTML
print re_is_html.search("<a>Foo</a>")
print re_is_html.search("<input type='submit' value='Ok' />")
print re_is_html.search("<br/>")

# We don't handle, but could with more tweaking:
print re_is_html.search("<br>")
print re_is_html.search("Foo &amp; bar")
print re_is_html.search("<input type='submit' value='Ok'>")

4

如果要从字符串文字创建正则表达式,则需要转义任何反斜杠:

var htmlRegex = new RegExp("<([A-Za-z][A-Za-z0-9]*)\\b[^>]*>(.*?)</\\1>");
// extra backslash added here ---------------------^ and here -----^

如果您使用正则表达式文字,则没有必要,但是您需要转义正斜杠:

var htmlRegex = /<([A-Za-z][A-Za-z0-9]*)\b[^>]*>(.*?)<\/\1>/;
// forward slash escaped here ------------------------^

另外,您的jsfiddle无效,因为您onload在另一个onload处理程序中分配了一个处理程序-左侧“框架和扩展”面板中设置的默认值是将JS包装为onload。将其更改为nowrap选项,并修复字符串文字转义并使其“起作用”(在每个人在注释中指出的约束内):http : //jsfiddle.net/wFWtc/4/

据我所知,JavaScript正则表达式没有反向引用。因此,您的表达的这一部分是:

</\1>

在JS中无法使用(但在其他一些语言中也可以使用)。



好吧,这将测试其中一个标签看起来不错,而其余标签则一无所有。不确定OP想要什么样的“有效性”。
nhahtdh

1
怎么样<br> <hr> <input...>@ user1240679?
CSᵠ

3

/<\/?[^>]*>/.test(str) 只检测它是否包含html标记,可能是xml


3

使用jQuery:

function isHTML(str) {
  return /^<.*?>$/.test(str) && !!$(str)[0];
}

2
isHTML("<foo>");//返回true isHTML("div");//如果div页面上有s,则返回true
ACK_stoverflow 2014年

@yekta-你在做什么?这应该检查字符串是否为html。据我所知,电子邮件不是html标签... isHTML('foo@bar.com')-> false //正确
gtournie

1
字符串可以是任何东西,如果您知道它的HTML标记,那么为什么要首先检查它的HTML,我不太理解您的意思。该@不是选择一个有效的语法。因此,当您将其传递给jQuery选择器时,它将引发异常(即$("you@example.com")from !!$(str)[0])。我专门指的是那!!$(str)[0] 部分。您刚刚编辑了答案,但是现在您要在jQuery执行任何操作之前先检查HTML。
yekta

我认为作者不想检查它是否只是一个字符串。这才是重点。他想要的是一个函数,它可以检查字符串是否是有效的HTML 标记,而不仅仅是HTML(否则,这有点愚蠢)。在阅读@ACK_stoverflow注释后,我更新了答案,但我确定应该使用一个简单的正则表达式。
gtournie

3

在这种情况下使用jQuery,最简单的形式是:

if ($(testString).length > 0)

如果是$(testString).length = 1,这意味着里面有一个HTML标签textStging


按照下面的答案(从“ With jQuery”开始,比该版本早四年编写!),请考虑从单个入口点选择多种用途的较差选择。 $()是CSS选择器操作。而且还是文本HTML序列化的DOM节点工厂。但是,根据对jQuery的依赖程度相同的其他答案,“ div”不是HTML,但是true如果<div>页面上存在任何元素,它将返回。这是一种非常非常糟糕的方法,因为我对几乎所有不必要地涉及jQuery的解决方案都抱有期望。(让它死。)
amcgregor

1

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

Q1:字符串是否包含HTML片段?

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

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

您可以看到此模式的使用在撰写本文时,所有现有答案中针对所有示例,以及一些…相当丑陋的WYSIWYG或Word生成的示例文本以及各种字符实体引用。

Q2:字符串是HTML文档吗?

HTML规范惊人松动,以什么它认为一个HTML文档。浏览器竭尽全力将几乎所有垃圾文本解析为HTML。两种方法:要么考虑所有HTML(因为如果提供了text/htmlContent-Type,则将花费大量精力尝试由用户代理将其解释为HTML)或寻找前缀标记:

<!DOCTYPE html>

就“格式良好”而言,“几乎没有其他要求”。以下是100%完整,完全有效的HTML文档,其中包含您认为已省略的每个HTML元素:

<!DOCTYPE html>
<title>Yes, really.</title>
<p>This is everything you need.

对。有关于如何形成“丢失”的元素,如明确的规则<html><head><body>。尽管我发现SO的语法高亮无法在没有显式提示的情况下正确地检测到它,这很可笑。


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

-1

NPM包is-html可以尝试解决此问题https://github.com/sindresorhus/is-html


我不理解它尝试使用的表达式,除了声明的doctype之外,该表达式都会失败,并且从完全依赖的HTML元素构造的“完全”模式会从附加依赖项中拉入,这会忽略这样的事实,即HTML并非如此,并且没有已经很长时间了 此外,基本模式显式提及<html><body>标签,它们都是完全可选的。“不匹配XML”测试表明了这一点。
amcgregor,

@amcgregor,如果您认为您的解决方案更好,则可能是isHTML存储库的一部分?并从regex101添加您的测试套件?这对社区来说将是宝贵的
Colin D

该库的基本目的是被误导的,并且在许多情况下会固有地出错,通常是由于存在不理解的标记而将其错误标记为非HTML。验证无法以这种方式成功。另外,一个简单的正则表达式或一个(编辑:成对的)librar [ies]… 我们可能已经忘记了如何编程,而Node / NPM并不是我通常希望利用,促进或鼓励使用的语言或工具链。 。
amcgregor

好的amcgergor,当我只是想帮助您时,您对我非常不利。我不同意npm被误导的前提。想象一下,您的堆栈溢出答案在将来会进行一些小的调整。作为使用您的库的开发人员,我会升级,并且我会得到更适当的行为。取而代之的是,我必须..忍受损坏的行为,或者重新访问此堆栈溢出答案才能进行编辑?那就是替代宇宙
Colin D

负?我在解释我的立场,以及为什么我不做本来似乎明智的事情。但是请注意,我链接的文章是较发炎的第一篇文章(预先链接)的后续文章,引起了很多讨论。他发表了一篇技术文章,也链接到该文章的底部。我用关于质量的证据来反驳您对返工的直觉。Ref:§7.2(和左页灾难&eslint)
amcgregor
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.