检查字符串是否为 html

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

我验证了我的正则表达式,它工作良好的 给你

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

小提琴在这里,但正则表达式不在那里运行

在我的机器上,代码运行得很好,但结果却是 false 而不是 true。 这里少了什么?

173792 次浏览

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

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 中工作(但可以在其他语言中工作)。

方法 # 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_NODE(nodeType的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);
}

备注: < br > 1。Array.from是 ES2015方法,可以用 [].slice.call(doc.body.childNodes)代替。< br > 2.some调用中的箭头函数可以替换为通常的匿名函数。

用于检查字符串是否为 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 元素。

一点小小的肯定:

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

这将搜索空标记(一些预定义的)和 /终止的 XHTML 空标记,并验证为 HTML,因为空标记 OR 将捕获标记名称,并尝试在字符串中找到它的结束标记,以验证为 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 标记,首先是空的,其余的需要一个结束标记。

这里解释演示: http://regex101.com/r/pE1mT5

使用 jQuery:

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

ZzzzBov 的回答 很好,但是它没有考虑到偏离的结束标记,例如:

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

还能捕获结束标记的版本可以是:

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

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

下面是我经常使用的一句粗心的俏皮话:

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

对于包含 <ANYTHING>的字符串,它基本上会返回 true

我所说的 ANYTHING,基本上是指除了空字符串之外的任何东西。

虽然不怎么样,但也只是一句俏皮话。

用法

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

正如你所看到的,它远非完美,但在某些情况下可能会为你做这项工作。

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

if ($(testString).length > 0)

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

这里所有的答案都是过度包容的,他们只是寻找 <后面跟着 >。没有完美的方法来检测字符串是否是 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'>")

我的解决办法是

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);

有一些花哨的解决方案,包括利用浏览器本身来尝试解析文本,识别是否构造了任何 DOM 节点,这将是... 缓慢的。或者正则表达式更快,但是... 可能不准确。这个问题还产生了两个截然不同的问题:

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

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

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

在写这篇文章的时候,你可以从所有现有的答案中看到 使用中的这种模式对所有的例子,加上一些... 相当丑陋的所见即所得或 Word 生成的示例文本和各种字符实体引用。

Q2: 字符串是 HTML 文档吗?

HTML 规范对于它所认为的 HTML 文档是非常松散的.浏览器会不遗余力地将几乎所有垃圾文本解析为 HTML。有两种方法: 要么只考虑所有的 HTML (因为如果使用 text/html Content-Type 交付,将花费大量精力使用 试试看将其解释为由用户代理的 HTML) ,要么寻找前缀标记:

<!DOCTYPE html>

就“格式良好”而言,除此之外,几乎没有什么是“必需的”。下面是一个包含您认为被省略的每个 HTML 元素的 100% 完整,完全有效的 HTML 文档:

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

是的。有关于如何形成“缺失”元素(如 <html><head><body>)的明确规则。不过我觉得有趣的是,在没有明确暗示的情况下,SO 的语法突显无法正确地检测到这一点。

有一个 NPM 包 is-html 可以尝试解决这个 https://github.com/sindresorhus/is-html

由于原始请求并没有说解决方案必须是 RegExp,只是说尝试使用 RegExp。我愿意献上这个。如果一个子元素可以被解析,那么这个子元素就是 HTML。注意,如果主体只包含注释、 CDATA 或服务器指令,则返回 false。

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

下面是我在自己的项目中使用的无正则表达式方法。

如果您试图在其他非 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

这在我的测试案例中对我有用,也可能对你有用。

对于 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);
}

虽然这是一个老主题,我只是想分享我为我的需要而写的解决方案:

function isHtml(input) {
return /<[a-z]+\d?(\s+[\w-]+=("[^"]*"|'[^']*'))*\s*\/?>|&#?\w+;/i.test(input);
}

它应该涵盖了我在这个帖子里发现的大部分棘手案件。在这个页面上用 document.body.innerTextdocument.body.innerHTML测试。

我希望它对某些人有用。 :)

投票最多的答案将验证下面的字符串作为 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>

检查的最佳方法是使用下面的函数作为工具

const containsHTML = (str: string) => /<[a-z][\s\S]*>/i.test(str);