Kiểm tra xem một chuỗi có phải là html hay không


98

Tôi có một chuỗi nhất định mà tôi muốn kiểm tra xem nó có phải là html hay không. Tôi đang sử dụng regex cho tương tự nhưng không nhận được kết quả thích hợp.

Tôi đã xác thực regex của mình và nó hoạt động tốt ở đây .

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

Đây là fiddle nhưng regex không chạy trong đó. http://jsfiddle.net/wFWtc/

Trên máy của tôi, mã chạy tốt nhưng tôi nhận được kết quả là false thay vì true. Cái gì còn thiếu ở đây?


5
Sử dụng trình phân tích cú pháp HTML để phân tích cú pháp HTML. Vui lòng đọc cái này nếu bạn chưa đọc.
Frédéric Hamidi

3
pháo đài câu hỏi tới, cần có một đống bot rằng aoutmatically sẽ thiết lập một lời nhận xét trên tất cả các câu hỏi với html và regex trong nó
Bartłomiej Lewandowski

3
Nó gần như phụ thuộc vào mức độ tinh vi bạn muốn từ séc. Bạn có thể kiểm tra xem chuỗi có chứa ít nhất một <và ít nhất một >hay không và gọi nó là HTML, hoặc bạn có thể kiểm tra xem nó có hợp lệ hay không với cú pháp HTML chính xác hoặc bất kỳ thứ gì ở giữa. Đối với những trường hợp đơn giản nhất, trình phân tích cú pháp HTML là không cần thiết.
JJJ

2
Tại sao bạn kiểm tra một chuỗi là HTML?
nhahtdh 17/03/13

2
@ user1240679: Định dạng đánh dấu hợp lệ? Loại giá trị nào? Theo nghĩa chặt chẽ nhất, bạn cần DTD để mô tả nó. Nói một cách dễ hiểu, bạn có thể muốn kiểm tra xem các thẻ đã khớp đúng chưa. Một trong 2 trường hợp trên không phải là công việc cho regex.
nhahtdh 17/03/13

Câu trả lời:


315

Một regex tốt hơn để sử dụng để kiểm tra xem một chuỗi có phải là HTML hay không là:

/^/

Ví dụ:

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

Trên thực tế, nó rất tốt, nó sẽ trả về truecho mỗi chuỗi được chuyển đến nó, đó là vì mọi chuỗi đều là HTML . Nghiêm túc mà nói, ngay cả khi nó được định dạng kém hoặc không hợp lệ, nó vẫn là HTML.

Nếu những gì bạn đang tìm kiếm là sự hiện diện của các phần tử HTML, thay vì chỉ đơn giản là bất kỳ nội dung văn bản nào, bạn có thể sử dụng một cái gì đó dọc theo các dòng:

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

Nó sẽ không giúp bạn phân tích cú pháp HTML theo bất kỳ cách nào, nhưng nó chắc chắn sẽ gắn cờ chuỗi chứa các phần tử HTML.


47
Tôi thực sự ngạc nhiên khi tôi không nhận được nhiều phiếu phản đối hơn cho snark.
zzzzBov

7
@clenemt, vậy bạn có coi a < b && a > clà HTML không?
zzzzBov

1
@zzzzBov bạn biết rằng bạn coi a<b && a>clà HTML ... Tôi ước gì việc phát hiện HTML có thể được đơn giản hóa nhiều như vậy. Phân tích cú pháp không bao giờ là dễ dàng.
oriadam

2
@oriadam, bối cảnh là để phát hiện các phần tử trong trường hợp đó. Nếu bạn sử dụng a < b && a > ctrình duyệt sẽ xoay ><nhân vật vào &gt;&lt;tổ chức một cách thích hợp. Thay vào đó, nếu bạn sử dụng a<b && a>c, trình duyệt sẽ giải thích đánh dấu là a<b && a>c</b>vì thiếu khoảng trắng có nghĩa là <bmở một <b>phần tử. Đây là bản demo nhanh về những gì tôi đang nói .
zzzzBov

4
Đây có lẽ là câu trả lời troll được bình chọn cao nhất mà tôi từng thấy. ;)
aandis

72

Phương pháp # 1 . Đây là hàm đơn giản để kiểm tra xem chuỗi có chứa dữ liệu HTML hay không:

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

Ý tưởng là cho phép trình phân tích cú pháp DOM của trình duyệt quyết định xem chuỗi được cung cấp có giống HTML hay không. Như bạn có thể thấy, nó chỉ đơn giản là kiểm tra ELEMENT_NODE( nodeTypetrong số 1).

Tôi đã thực hiện một vài thử nghiệm và có vẻ như nó hoạt động:

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

Giải pháp này sẽ phát hiện đúng chuỗi HTML, tuy nhiên nó có tác dụng phụ là img / vide / etc. thẻ sẽ bắt đầu tải xuống tài nguyên sau khi được phân tích cú pháp trong innerHTML.

Phương pháp # 2 . Một phương pháp khác sử dụng DOMParser và không có tác dụng phụ khi tải tài nguyên:

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

Ghi chú:
1. Array.fromlà phương pháp ES2015, có thể được thay thế bằng [].slice.call(doc.body.childNodes).
2. Hàm mũi tên trong somecuộc gọi có thể được thay thế bằng hàm ẩn danh thông thường.


3
Đây là một ý tưởng tuyệt vời. Tuy nhiên, chức năng này không thể phát hiện thẻ đóng (tức là isHTML("</a>") --> false).
Lewis

9
Giải pháp tuyệt vời! .. Tác động tiêu cực duy nhất của nó là nếu html của bạn chứa bất kỳ tài nguyên tĩnh nào như thuộc tính src image .. innerHTMLsẽ buộc trình duyệt bắt đầu tìm nạp các tài nguyên đó. :(
Jose Browne

@JoseBrowne ngay cả khi nó không được nối vào DOM?
kuus

1
@kuus Có, ngay cả khi không tiếp tục. Sử dụng giải pháp DOMParser.
dfsq

1
Ý tưởng hay, nhưng câu trả lời được chấp nhận sẽ không tốt hơn cho hiệu suất sao? Đặc biệt là nếu bạn có một chuỗi lớn (dự định chơi chữ) hoặc nếu bạn phải sử dụng bài kiểm tra này nhiều.
DerpyNerd

13

Một chút xác thực với:

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

Điều này tìm kiếm các thẻ trống (một số được xác định trước) và / các thẻ trống XHTML đã kết thúc và xác thực dưới dạng HTML vì thẻ trống HOẶC sẽ nắm bắt tên thẻ và cố gắng tìm thẻ đóng ở đâu đó trong chuỗi để xác thực dưới dạng HTML.

Bản demo giải thích: http://regex101.com/r/cX0eP2

Cập nhật:

Hoàn thành xác thực với:

/<(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) 

Điều này thực hiện xác thực thích hợp vì nó chứa TẤT CẢ các thẻ HTML, những thẻ trống đầu tiên, tiếp theo là những thẻ còn lại cần thẻ đóng.

Bản demo giải thích tại đây: http://regex101.com/r/pE1mT5


1
Chỉ cần lưu ý rằng regex dưới cùng hoạt động nhưng nó sẽ không phát hiện ra các thẻ html không được đóng chặt như "'<strong> hello world". được cấp, đây là html bị hỏng do đó nên được coi là một chuỗi nhưng đối với các mục đích thực tế, ứng dụng của bạn cũng có thể muốn phát hiện chúng.
TK123

HTML được thiết kế với sự lưu ý đến tác nhân người dùng. Thẻ "không hợp lệ" không phải là không hợp lệ, chúng chỉ là không xác định và được phép. Các thuộc tính "không hợp lệ" không phải là không hợp lệ ... Điều này đặc biệt đáng chú ý khi một thuộc tính bắt đầu liên quan đến "các thành phần web" và công nghệ như JSX, kết hợp HTML và các mô tả thành phần phong phú hơn, thường tạo ra DOM bóng. Tát cái này vào một tệp và đánh giá document.querySelector('strange')- nó sẽ hoạt động.
amcgregor

(Để tóm tắt: do cách đặc tả được viết, cố gắng "Validate" đánh dấu HTML cơ bản là một việc khó khăn Các liên kết cho một tài liệu HTML mẫu với một yếu tố "không hợp lệ", ở đó, là một. 100% đầy đủ hình thành, tài liệu HTML hoàn chỉnh —và đã có từ năm 1997 — như một ví dụ khác.)
amcgregor

9

Câu trả lời của zzzzBov ở trên là tốt, nhưng nó không giải thích cho các thẻ đóng bị lạc, chẳng hạn như:

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

Một phiên bản cũng bắt các thẻ đóng có thể là:

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

Tốt hơn là nên đề xuất một bản chỉnh sửa, thay vì đăng cái này dưới dạng nhận xét.
Zlatin Zlatev

Tôi nghĩ bạn có nghĩa là <[a-z/][\s\S]*>- lưu ý dấu gạch chéo trong nhóm đầu tiên.
Ryan Guill

7

Đây là một lớp lót cẩu thả mà tôi thường sử dụng:

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

Về cơ bản, nó sẽ trả về truecho các chuỗi có chứa một <theo ANYTHINGsau bởi> .

Bởi ANYTHING , tôi có nghĩa là về cơ bản bất cứ điều gì ngoại trừ một chuỗi rỗng.

Nó không tuyệt vời, nhưng nó là một lớp lót.

Sử dụng

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

Như bạn có thể thấy, nó còn lâu mới hoàn hảo, nhưng có thể thực hiện công việc cho bạn trong một số trường hợp.


1
đúng thứ tôi cần. Không có gì cầu kỳ, chỉ cần sạch sẽ. Cảm ơn!
moeiscool

6

Tất cả các câu trả lời ở đây là bao hàm quá mức, họ chỉ cần tìm <theo sau >. Không có cách hoàn hảo nào để phát hiện một chuỗi có phải là HTML hay không, nhưng bạn có thể làm tốt hơn.

Dưới đây, chúng tôi tìm kiếm các thẻ kết thúc và sẽ chặt chẽ hơn và chính xác hơn:

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

Và nó đang hoạt động ở đây:

# 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

Nếu bạn đang tạo regex từ một chuỗi ký tự, bạn cần phải loại bỏ bất kỳ dấu gạch chéo ngược nào:

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

Điều này là không cần thiết nếu bạn sử dụng ký tự regex, nhưng sau đó bạn cần thoát khỏi các dấu gạch chéo về phía trước:

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

Ngoài ra, jsfiddle của bạn không hoạt động vì bạn đã chỉ định một onloadtrình xử lý bên trong một onloadtrình xử lý khác - mặc định như được đặt trong bảng Khung công tác & Tiện ích mở rộng ở bên trái là bọc JS trong một onload. Thay đổi tùy chọn đó thành tùy chọn nowrap và sửa chuỗi thoát theo nghĩa đen và nó "hoạt động" (trong các ràng buộc mà mọi người đã chỉ ra trong nhận xét): http://jsfiddle.net/wFWtc/4/

Theo như tôi biết thì biểu thức chính quy JavaScript không có tham chiếu ngược. Vì vậy, phần này của biểu thức của bạn:

</\1>

sẽ không hoạt động trong JS (nhưng sẽ hoạt động trong một số ngôn ngữ khác).



Chà, điều này sẽ kiểm tra xem một trong các thẻ trông ổn, nhưng không có gì về phần còn lại. Không chắc OP muốn loại "tính hợp lệ" nào.
nhahtdh 17/03/13

1
còn <br> <hr> <input...>@ user1240679 thì sao?
CSᵠ

3

/<\/?[^>]*>/.test(str) Chỉ phát hiện xem nó có chứa các thẻ html hay không, có thể là một xml


27 is < 42, and 96 > 42. Đây không phải là HTML.
amcgregor

3

Với jQuery:

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

2
isHTML("<foo>");// trả về true isHTML("div");// trả về true nếu có divs trên trang
ACK_stoverflow

@yekta - Bạn đang xem về điều gì? Điều này được cho là để kiểm tra xem chuỗi có phải là html hay không. Một email không phải là một thẻ html như xa như tôi biết ... isHTML ('foo@bar.com ') -> sai // đúng
gtournie

1
Một chuỗi có thể là bất cứ thứ gì, nếu bạn biết thẻ HTML của nó thì tại sao phải kiểm tra xem HTML của nó ngay từ đầu, tôi không hoàn toàn theo ý bạn. Đây @không phải là một cú pháp hợp lệ cho một bộ chọn. Vì vậy, khi bạn chuyển nó đến một bộ chọn jQuery, nó sẽ ném ra một ngoại lệ (tức là $("you@example.com")from !!$(str)[0]). Tôi đang đề cập cụ thể đến !!$(str)[0] phần này. Bạn vừa chỉnh sửa câu trả lời của mình, nhưng bây giờ bạn đang kiểm tra HTML trước khi jQuery thực hiện bất kỳ điều gì.
yekta

Tôi không nghĩ tác giả muốn kiểm tra xem nó có phải chỉ là một chuỗi hay không. Đó là điểm. Những gì anh ấy muốn là một hàm có thể kiểm tra xem chuỗi có phải là một thẻ HTML hợp lệ hay không, chứ không chỉ HTML (nếu không thì điều này hơi ngu ngốc). Tôi đã cập nhật câu trả lời của mình sau khi tôi đọc nhận xét @ACK_stoverflow, nhưng tôi chắc chắn rằng một regex đơn giản sẽ làm được điều đó.
gtournie

3

Sử dụng jQuery trong trường hợp này, dạng đơn giản nhất sẽ là:

if ($(testString).length > 0)

Nếu $(testString).length = 1, điều này có nghĩa là có một thẻ HTML bên trong textStging.


Theo câu trả lời ngay bên dưới (bắt đầu bằng "Với jQuery", được viết trước câu trả lời này bốn năm!), Hãy xem xét việc lựa chọn nhiều lần sử dụng từ một điểm nhập duy nhất. $()là một hoạt động của bộ chọn CSS. Nhưng cũng là một nhà máy sản xuất nút DOM từ tuần tự hóa HTML văn bản. Nhưng cũng ... như theo câu trả lời khác có cùng sự phụ thuộc vào jQuery, "div" không phải là HTML, nhưng sẽ trả về truenếu có bất kỳ <div>phần tử nào tồn tại trên trang. Đây là một cách tiếp cận rất, rất tệ, như tôi đã mong đợi với hầu hết mọi giải pháp không cần đến jQuery. (Hãy để nó chết.)
amcgregor

1

Có những giải pháp ưa thích liên quan đến việc sử dụng chính trình duyệt để cố gắng phân tích cú pháp văn bản, xác định xem có bất kỳ nút DOM nào được xây dựng hay không, điều này sẽ… chậm. Hoặc biểu thức chính quy sẽ nhanh hơn, nhưng… có khả năng không chính xác. Cũng có hai câu hỏi rất khác biệt nảy sinh từ vấn đề này:

Q1: Một chuỗi có chứa các đoạn HTML không?

Chuỗi có phải là một phần của tài liệu HTML, chứa đánh dấu phần tử HTML hoặc các thực thể được mã hóa không? Điều này có thể được sử dụng như một chỉ báo rằng chuỗi có thể yêu cầu tẩy trắng / làm vệ sinh hoặc giải mã thực thể:

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

Bạn có thể thấy mẫu này được sử dụng đối với tất cả các ví dụ từ tất cả các câu trả lời hiện có tại thời điểm viết bài này, cộng với một số… văn bản mẫu khá ghê tởm do WYSIWYG- hoặc Word tạo và nhiều tham chiếu thực thể ký tự.

Câu hỏi 2: Chuỗi có phải là tài liệu HTML không?

Đặc tả HTML lỏng lẻo một cách đáng kinh ngạc so với những gì nó coi là một tài liệu HTML . Các trình duyệt có độ dài cực cao để phân tích gần như bất kỳ văn bản rác nào dưới dạng HTML. Hai cách tiếp cận: hoặc chỉ xem xét mọi thứ HTML (vì nếu được phân phối với text/htmlLoại-Nội dung, thì tác nhân người dùng sẽ phải nỗ lực rất nhiều để cố gắng diễn giải nó thành HTML) hoặc tìm kiếm điểm đánh dấu tiền tố:

<!DOCTYPE html>

Về mặt "hình thành tốt", điều đó, và hầu như không có gì khác là "bắt buộc". Sau đây là tài liệu HTML hoàn chỉnh, hoàn toàn hợp lệ 100% chứa mọi phần tử HTML mà bạn cho rằng đang bị bỏ qua:

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

Đúng vậy. Có những quy tắc rõ ràng về cách tạo "mất tích" các yếu tố như <html>, <head>, và <body>. Mặc dù tôi thấy khá thú vị khi đánh dấu cú pháp của SO không phát hiện được đúng cách mà không có gợi ý rõ ràng.


0

Giải pháp của tôi là

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

Biểu thức chính quy của bạn có vẻ rất bị lỗi so với một biểu thức toàn diện hơn và việc yêu cầu xử lý trước (thay thế ban đầu) là rất đáng tiếc.
amcgregor

-1

Có một gói NPM là-html có thể cố gắng giải quyết vấn đề này https://github.com/sindresorhus/is-html


Tôi không hiểu biểu thức mà nó đang cố gắng sử dụng nhưng không thành công ngoại trừ loại tài liệu đã khai báo và mẫu "đầy đủ" được xây dựng từ các phần tử HTML đã biết được kéo vào từ một phần phụ thuộc bổ sung bỏ qua thực tế rằng đó không phải là cách HTML hoạt động và không trong một thời gian rất dài. Ngoài ra, mẫu cơ sở đề cập rõ ràng <html><body>thẻ, cả hai đều là tùy chọn hoàn toàn . Kiểm tra "không khớp với XML" đang nói.
amcgregor

@amcgregor nếu bạn nghĩ giải pháp của mình tốt hơn có thể đóng góp vào repo isHTML? và thêm bộ thử nghiệm của bạn từ regex101? nó sẽ có giá trị đối với cộng đồng
Colin D

Mục đích cơ bản của thư viện đó là sai lầm và vốn dĩ sẽ sai trong một số lượng lớn trường hợp, thường là do gắn cờ sai là không phải HTML do sự hiện diện của các thẻ mà nó không hiểu; xác nhận không thể thành công theo cách này. Ngoài ra, một regex đơn giản hoặc một (chỉnh sửa: cặp ) [ies]… chúng ta có thể đã quên cách lập trình và Node / NPM không phải là một ngôn ngữ hoặc chuỗi công cụ mà tôi thường muốn sử dụng, đóng góp hoặc khuyến khích sử dụng .
amcgregor

Được rồi, bạn đang đối xử khá tiêu cực với tôi khi tôi chỉ cố gắng giúp đỡ. Tôi không đồng ý với tiền đề của npm bị hiểu sai. Hãy tưởng tượng câu trả lời tràn ngăn xếp của bạn được đưa ra với một chỉnh sửa nhỏ trong tương lai. Tôi, với tư cách là nhà phát triển sử dụng thư viện của bạn, chỉ cần nâng cấp và tôi sẽ có hành vi đúng đắn hơn. Thay vào đó, tôi phải .... sống với hành vi bị hỏng hoặc truy cập lại câu trả lời tràn ngăn xếp này để nhận các chỉnh sửa của bạn? Đó là vũ trụ thay thế
Colin D

Tiêu cực? Tôi đang giải thích lập trường của mình và lý do tại sao tôi không làm điều mà nếu không thì có vẻ là một điều hợp lý. Tuy nhiên, lưu ý rằng bài viết tôi đã liên kết là bài viết tiếp theo từ bài viết đầu tiên có tính viêm nhiễm hơn một chút (được liên kết lên phía trước) tạo ra nhiều cuộc thảo luận. Ông đã xuất bản một bài báo kỹ thuật , cũng được liên kết ở đó, về phía dưới. Tôi phản bác lại cảm giác của bạn về việc làm lại bằng bằng chứng về chất lượng. Tham khảo: §7.2 (& thảm họa bên trái & eslint)
amcgregor
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.