Periksa apakah sebuah string adalah html atau bukan


100

Saya memiliki string tertentu yang ingin saya periksa apakah itu html atau bukan. Saya menggunakan regex untuk hal yang sama tetapi tidak mendapatkan hasil yang sesuai.

Saya memvalidasi regex saya dan berfungsi dengan baik di sini .

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

Ini biola tetapi regex tidak berjalan di sana. http://jsfiddle.net/wFWtc/

Di mesin saya, kodenya berjalan dengan baik tetapi saya mendapatkan kesalahan alih-alih benar sebagai hasilnya. Apa yang hilang di sini?


5
Gunakan pengurai HTML untuk mengurai HTML. Silakan baca ini jika Anda belum melakukannya.
Frédéric Hamidi

3
pertanyaan terus berdatangan, harus ada bot tumpukan yang secara otomatis akan memberikan komentar pada setiap pertanyaan dengan html dan regex di dalamnya
Bartlomiej Lewandowski

3
Ini agak tergantung pada tingkat kecanggihan yang Anda inginkan dari cek tersebut. Anda dapat memeriksa apakah string berisi setidaknya satu <dan setidaknya satu >dan menyebutnya HTML, atau Anda dapat memeriksa apakah itu benar-benar valid dengan sintaks HTML yang benar, atau apa pun dari keduanya. Untuk kasus yang paling sederhana, pengurai HTML tidak diperlukan.
JJJ

3
Mengapa Anda memeriksa bahwa string adalah HTML?
nhahtdh

2
@ user1240679: Format markup valid? Validitas seperti apa? Dalam arti yang paling sempit, Anda memerlukan DTD untuk mendeskripsikannya. Dalam arti yang longgar, Anda mungkin ingin memeriksa apakah tag sudah cocok dengan benar. Salah satu dari 2 kasus di atas bukanlah tugas untuk regex.
nhahtdh

Jawaban:


319

Regex yang lebih baik untuk digunakan untuk memeriksa apakah suatu string adalah HTML adalah:

/^/

Sebagai contoh:

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

Faktanya, ini sangat bagus, sehingga akan kembali trueuntuk setiap string yang diteruskan ke sana, karena setiap string adalah HTML . Serius, meskipun formatnya buruk atau tidak valid, itu masih HTML.

Jika yang Anda cari adalah keberadaan elemen HTML, bukan hanya konten teks apa pun, Anda dapat menggunakan sesuatu di sepanjang baris:

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

Ini tidak akan membantu Anda mengurai HTML dengan cara apa pun, tetapi pasti akan menandai string sebagai mengandung elemen HTML.


52
Sejujurnya saya terkejut saya tidak mendapatkan lebih banyak suara negatif untuk snark tersebut.
zzzzBov

8
@clenemt, jadi Anda menganggapnya a < b && a > cHTML?
zzzzBov

1
@zzzzBov Anda tahu bahwa Anda menganggap a<b && a>cHTML ... Saya berharap deteksi HTML dapat disederhanakan sebanyak itu. Parsing tidak pernah mudah.
oriadam

2
@oriadam, konteksnya adalah untuk mendeteksi elemen dalam kasus tersebut. Jika Anda menggunakan a < b && a > cbrowser akan mengubah >dan <karakter ke &gt;dan &lt;entitas tepat. Jika, sebaliknya, Anda menggunakan a<b && a>cbrowser akan menafsirkan markup a<b && a>c</b>karena kurangnya spasi berarti <bmembuka <b>elemen. Berikut demo singkat tentang apa yang saya bicarakan .
zzzzBov

4
Ini mungkin jawaban troll dengan suara terbanyak yang pernah saya lihat. ;)
aandis

74

Metode # 1 . Berikut adalah fungsi sederhana untuk menguji apakah string berisi data 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;
}

Idenya adalah mengizinkan pengurai DOM browser untuk memutuskan apakah string yang diberikan terlihat seperti HTML atau tidak. Seperti yang Anda lihat, ini hanya memeriksa ELEMENT_NODE( nodeTypedari 1).

Saya membuat beberapa tes dan sepertinya berhasil:

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

Solusi ini akan mendeteksi string HTML dengan baik, namun memiliki efek samping seperti img / vide / etc. tag akan mulai mengunduh sumber daya setelah diurai dalam innerHTML.

Metode # 2 . Metode lain menggunakan DOMParser dan tidak memiliki efek samping pemuatan sumber daya:

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

Catatan:
1. Array.fromadalah metode ES2015, dapat diganti dengan [].slice.call(doc.body.childNodes).
2. Fungsi panah dalam somepanggilan dapat diganti dengan fungsi anonim biasa.


3
Ini ide yang bagus. Namun, fungsi ini tidak dapat mendeteksi tag penutup (yaitu isHTML("</a>") --> false).
Lewis

9
Solusi hebat! .. Satu-satunya efek samping negatif adalah jika html Anda berisi sumber daya statis seperti atribut src gambar .. innerHTMLakan memaksa browser untuk mulai mengambil sumber daya tersebut. :(
Jose Browne

@JoseBrowne meskipun tidak ditambahkan ke DOM?
kuus

1
@kuus Ya, meskipun tidak menambahkan. Gunakan solusi DOMParser.
dfsq

1
Ide bagus, tetapi bukankah jawaban yang diterima lebih baik untuk kinerja? Terutama jika Anda memiliki string besar (permainan kata-kata) atau jika Anda harus sering menggunakan tes ini.
DerpyNerd

13

Sedikit validasi dengan:

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

Ini mencari tag kosong (beberapa sudah ditentukan sebelumnya) dan / menghentikan tag kosong XHTML dan memvalidasi sebagai HTML karena tag kosong ATAU akan menangkap nama tag dan mencoba menemukan tag penutupnya di suatu tempat dalam string untuk divalidasi sebagai HTML.

Demo yang dijelaskan: http://regex101.com/r/cX0eP2

Memperbarui:

Lengkapi validasi dengan:

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

Ini melakukan validasi yang tepat karena berisi ALL tag HTML, yang kosong terlebih dahulu diikuti oleh sisanya yang memerlukan tag penutup.

Demo dijelaskan di sini: http://regex101.com/r/pE1mT5


1
Sebagai catatan, regex bawah berfungsi tetapi tidak akan mendeteksi tag html yang tidak ditutup seperti "'<strong> hello world". diberikan ini adalah html rusak oleh karena itu harus diperlakukan sebagai string tetapi untuk tujuan praktis aplikasi Anda mungkin ingin mendeteksinya juga.
TK123

HTML dirancang dengan mempertimbangkan pengampunan agen pengguna. Tag "tidak valid" tidak valid, hanya tidak dikenal, dan diizinkan. Atribut "tidak valid" tidak valid… Hal ini terutama penting ketika seseorang mulai melibatkan "komponen web" dan teknologi seperti JSX, yang menggabungkan HTML dan deskripsi komponen yang lebih kaya, biasanya menghasilkan shadow DOM. Tampar ini di file dan eval document.querySelector('strange')- itu akan berhasil.
amcgregor

(Untuk meringkas: karena bagaimana spesifikasi ditulis, mencoba untuk "memvalidasi" markup HTML pada dasarnya adalah tugas bodoh. Tautan yang diberikan ke dokumen HTML sampel dengan elemen "tidak valid", di sana, 100% terbentuk sepenuhnya, melengkapi dokumen HTML — dan sudah ada sejak 1997 — sebagai contoh lain.)
amcgregor

10

Jawaban zzzzBov di atas bagus, tetapi tidak memperhitungkan tag penutup yang tersesat, seperti misalnya:

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

Versi yang juga menangkap tag penutup bisa jadi ini:

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

Mungkin lebih baik menyarankan pengeditan, daripada memposting ini sebagai komentar.
Zlatin Zlatev

Saya pikir maksud Anda <[a-z/][\s\S]*>- perhatikan garis miring di kelompok pertama.
Ryan Guill

7

Ini satu baris ceroboh yang saya gunakan dari waktu ke waktu:

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

Ini pada dasarnya akan mengembalikan truestring yang berisi <diikuti oleh ANYTHINGdiikuti oleh> .

Oleh ANYTHING , maksud saya pada dasarnya apa pun kecuali string kosong.

Itu tidak bagus, tapi itu satu baris.

Pemakaian

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

Seperti yang Anda lihat, ini jauh dari sempurna, tetapi mungkin berhasil untuk Anda dalam beberapa kasus.


1
hanya apa yang saya butuhkan. Tidak ada yang mewah, bersih saja. Terima kasih!
moeiscool

6

Semua jawaban di sini terlalu inklusif, mereka hanya mencari <diikuti oleh >. Tidak ada cara sempurna untuk mendeteksi apakah suatu string adalah HTML, tetapi Anda dapat melakukannya dengan lebih baik.

Di bawah ini kami mencari tag akhir , dan akan jauh lebih ketat dan lebih akurat:

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

Dan ini dia aksinya:

# 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

Jika Anda membuat regex dari string literal, Anda perlu menghindari garis miring terbalik:

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

Ini tidak diperlukan jika Anda menggunakan literal regex, tetapi kemudian Anda perlu keluar dari garis miring:

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

Juga jsfiddle Anda tidak berfungsi karena Anda menetapkan onloadpenangan di dalam penangan lain onload- default seperti yang ditetapkan di panel Kerangka & Ekstensi di sebelah kiri adalah untuk membungkus JS dalam onload. Ubah itu menjadi opsi nowrap dan perbaiki string literal escaping dan itu "berfungsi" (dalam batasan yang ditunjukkan semua orang di komentar): http://jsfiddle.net/wFWtc/4/

Sejauh yang saya tahu, ekspresi reguler JavaScript tidak memiliki referensi balik. Jadi ini bagian dari ekspresi Anda:

</\1>

tidak akan berfungsi di JS (tetapi akan berfungsi di beberapa bahasa lain).



Nah, ini akan menguji bahwa salah satu tag terlihat baik-baik saja, tetapi tidak tentang yang lainnya. Tidak yakin "validitas" seperti apa yang diinginkan OP.
nhahtdh

1
bagaimana dengan <br> <hr> <input...>@ user1240679?
CSᵠ

3

/<\/?[^>]*>/.test(str) Hanya mendeteksi apakah itu berisi tag html, mungkin xml


27 is < 42, and 96 > 42. Ini bukan HTML.
amcgregor

3

Dengan jQuery:

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

2
isHTML("<foo>");// mengembalikan nilai benar isHTML("div");// mengembalikan nilai benar jika ada divpada halaman
ACK_stoverflow

@yekta - Apa yang kamu ambil tentang? Ini seharusnya untuk memeriksa apakah string itu html atau tidak. Email bukanlah tag html sejauh yang saya tahu ... isHTML ('foo@bar.com ') -> false // benar
gtournie

1
Sebuah string bisa apa saja, jika Anda tahu itu adalah tag HTML lalu mengapa memeriksa apakah HTML-nya di tempat pertama, saya tidak begitu mengikuti maksud Anda. Ini @bukan sintaks yang valid untuk pemilih. Jadi, ketika Anda meneruskannya ke pemilih jQuery, itu akan memunculkan pengecualian (yaitu $("you@example.com")dari !!$(str)[0]). Saya secara khusus mengacu pada !!$(str)[0] porsinya. Anda baru saja mengedit jawaban Anda, tetapi sekarang Anda memeriksa HTML sebelum jQuery melakukan apa pun.
yekta

Saya rasa penulis tidak ingin memeriksa apakah itu hanya sebuah string. Itulah intinya. Apa yang dia inginkan adalah sebuah fungsi yang dapat memeriksa apakah string itu adalah tag HTML yang valid , bukan hanya HTML (jika tidak, ini agak bodoh). Saya memperbarui jawaban saya setelah saya membaca komentar @ACK_stoverflow, tetapi saya yakin regex sederhana dapat melakukannya.
gtournie

3

Menggunakan jQuery dalam kasus ini, bentuk paling sederhana adalah:

if ($(testString).length > 0)

Jika $(testString).length = 1, ini berarti ada satu tag HTML di dalamnya textStging.


Sesuai jawaban di bawah ini (dimulai dengan "Dengan jQuery", ditulis empat tahun sebelum yang ini!), Pertimbangkan pilihan yang buruk dari beberapa penggunaan dari satu titik masuk. $()adalah operasi pemilih CSS. Tetapi juga pabrik simpul DOM dari serialisasi HTML tekstual. Tetapi juga… sesuai jawaban lain yang menderita ketergantungan yang sama pada jQuery, "div" bukanlah HTML, tetapi itu akan kembali truejika ada <div>elemen di halaman. Ini adalah pendekatan yang sangat, sangat buruk, seperti yang saya harapkan dengan hampir semua solusi yang tidak perlu melibatkan jQuery. (Biarkan mati.)
amcgregor

2

Ada solusi mewah yang melibatkan penggunaan browser itu sendiri untuk mencoba mengurai teks, mengidentifikasi jika ada node DOM yang dibuat, yang akan… lambat. Atau ekspresi reguler yang akan lebih cepat, tetapi… berpotensi tidak akurat. Ada juga dua pertanyaan yang sangat berbeda yang muncul dari masalah ini:

T1: Apakah string berisi fragmen HTML?

Apakah string bagian dari dokumen HTML, berisi markup elemen HTML atau entitas yang dikodekan? Ini dapat digunakan sebagai indikator bahwa string mungkin memerlukan pemutihan / sanitasi atau dekode entitas:

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

Anda dapat melihat pola ini digunakan terhadap semua contoh dari semua jawaban yang ada pada saat penulisan ini, ditambah beberapa… contoh teks yang dihasilkan WYSIWYG atau Word yang agak mengerikan dan berbagai referensi entitas karakter.

Q2: Apakah string merupakan dokumen HTML?

The spesifikasi HTML mengejutkan longgar untuk apa yang dianggap sebuah dokumen HTML . Peramban berusaha sangat keras untuk mengurai hampir semua teks sampah sebagai HTML. Dua pendekatan: pertimbangkan semua HTML (karena jika dikirimkan dengan text/htmlJenis Konten, upaya besar akan dilakukan untuk mencoba menafsirkannya sebagai HTML oleh agen pengguna) atau mencari penanda awalan:

<!DOCTYPE html>

Dalam istilah "pembentukan yang baik", itu, dan hampir tidak ada hal lain yang "diperlukan". Berikut ini adalah 100% lengkap, dokumen HTML valid penuh yang berisi setiap elemen HTML yang menurut Anda sedang dihilangkan:

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

Ya. Ada aturan eksplisit tentang bagaimana membentuk "hilang" unsur-unsur seperti <html>, <head>, dan <body>. Meskipun saya merasa agak lucu bahwa penyorotan sintaks SO gagal mendeteksi itu dengan benar tanpa petunjuk eksplisit.


0

Solusi saya adalah

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

Ekspresi reguler Anda tampaknya sangat rusak vs. ekspresi yang lebih komprehensif , dan sangat disayangkan membutuhkan pemrosesan awal (penggantian awal).
amcgregor

-1

Ada paket NPM is-html yang dapat mencoba menyelesaikan https://github.com/sindresorhus/is-html ini


Saya tidak memahami ekspresi yang coba digunakannya yang gagal kecuali pada doctype yang dideklarasikan, dan pola "penuh" yang dibangun dari elemen HTML yang diketahui ditarik dari ketergantungan tambahan mengabaikan fakta bahwa HTML tidak bekerja, dan tidak sudah sangat, sangat lama. Selain itu, pola dasar secara eksplisit menyebutkan <html>dan memberi <body>tag, keduanya sepenuhnya opsional . Tes "tidak cocok XML" memberi tahu.
amcgregor

@ amcgregor jika menurut Anda solusi Anda lebih baik mungkin berkontribusi pada repo isHTML? dan menambahkan rangkaian pengujian Anda dari regex101? itu akan menjadi berharga bagi komunitas
Colin D

Tujuan mendasar dari pustaka tersebut salah arah dan secara inheren akan salah dalam banyak kasus, biasanya dengan penandaan palsu sebagai bukan HTML karena adanya tag yang tidak dipahami; validasi tidak bisa berhasil dengan cara ini. Selain itu, regex sederhana atau (edit: pair of ) librar [ies]… kita mungkin lupa cara memprogram , dan Node / NPM bukanlah bahasa atau toolchain yang biasanya ingin saya gunakan, sumbangkan, atau dorong penggunaan .
amcgregor

Baiklah amcgergor, Anda bersikap sangat negatif kepada saya ketika saya hanya mencoba membantu. Saya tidak setuju dengan premis npm yang salah arah. Bayangkan jawaban stack overflow Anda muncul dengan sedikit perubahan di masa depan. Saya, sebagai pengembang yang menggunakan perpustakaan Anda, hanya akan memutakhirkan, dan saya akan mendapatkan perilaku yang lebih tepat. Sebaliknya, saya harus .... hidup dengan perilaku yang rusak atau mengunjungi kembali jawaban stack overflow ini untuk mendapatkan hasil edit Anda? Itulah alam semesta alternatif
Colin D

Negatif? Saya menjelaskan pendirian saya dan mengapa saya tidak akan melakukan apa yang kelihatannya masuk akal. Perhatikan, bagaimanapun, bahwa artikel yang saya tautkan adalah tindak lanjut dari yang pertama sedikit lebih menghasut (ditautkan di depan) yang menghasilkan banyak diskusi. Dia menerbitkan makalah teknis , juga ditautkan di sana, ke bagian bawah. Saya melawan firasat Anda tentang bekerja kembali dengan bukti tentang kualitas. Ref: §7.2 (& the left-pad disaster & eslint)
amcgregor
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.