Bir dizenin html olup olmadığını kontrol edin


103

Html olup olmadığını kontrol etmek istediğim belirli bir dizem var. Aynı için normal ifadeyi kullanıyorum ancak doğru sonucu alamıyorum.

Normal ifademi doğruladım ve burada sorunsuz çalışıyor .

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

İşte keman burada ama normal ifade orada çalışmıyor. http://jsfiddle.net/wFWtc/

Makinemde kod iyi çalışıyor ancak sonuç olarak doğru yerine yanlış alıyorum. Burada ne eksik?


5
HTML'yi ayrıştırmak için bir HTML ayrıştırıcı kullanın. Lütfen okuyun bu zaten değil varsa.
Frédéric Hamidi

3
soru gelmeye devam ederse, içinde html ve regex bulunan her soruya açıklayıcı bir şekilde yorum yapacak bir yığın bot olmalıdır
Bartlomiej Lewandowski

3
Bu, kontrolden ne kadar karmaşıklık istediğinize bağlı. Dizenin en az bir <ve en az bir tane içerip içermediğini kontrol edebilir >ve ona HTML diyebilirsiniz veya doğru HTML sözdizimi veya aradaki herhangi bir şeyle kesinlikle geçerli olup olmadığını kontrol edebilirsiniz. En basit durumlarda HTML ayrıştırıcı gerekli değildir.
JJJ

3
Neden bir dizenin HTML olup olmadığını kontrol ediyorsunuz?
nhahtdh

2
@ user1240679: Geçerli biçimlendirme biçimi? Ne tür bir geçerlilik? En katı anlamda, onu tanımlamak için DTD'ye ihtiyacınız var. Geniş anlamda, etiketlerin doğru şekilde eşleşip eşleşmediğini kontrol etmek isteyebilirsiniz. Yukarıdaki 2 durumdan herhangi biri normal ifade için iş değildir.
nhahtdh

Yanıtlar:


324

Bir dizenin HTML olup olmadığını kontrol etmek için kullanılacak daha iyi bir normal ifade:

/^/

Örneğin:

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

Aslında, o kadar iyidir ki, kendisine geçirilen her dizge trueiçin geri döner , çünkü her dizge HTML'dir . Cidden, kötü biçimlendirilmiş veya geçersiz olsa bile, hala HTML'dir.

Aradığınız şey herhangi bir metin içeriği yerine HTML öğelerinin varlığı ise, şu satırlar boyunca bir şey kullanabilirsiniz:

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

HTML'yi hiçbir şekilde ayrıştırmanıza yardımcı olmaz, ancak dizeyi kesinlikle HTML öğeleri içeriyor olarak işaretler.


54
Sinsi için daha fazla olumsuz oy almadığıma gerçekten şaşırdım.
zzzzBov

8
@clenemt, a < b && a > cHTML olmayı mı düşünüyorsunuz ?
zzzzBov

1
@zzzzBov, a<b && a>cHTML olarak gördüğünüzü biliyorsunuz ... Keşke HTML algılama bu kadar basitleştirilseydi. Ayrıştırma asla kolay değildir.
oriadam

2
@oriadam, bağlam bu durumda öğeleri tespit etmek içindi. a < b && a > cTarayıcı kullanırsanız >ve <karakterlerini &gt;ve &lt;varlıklarını uygun şekilde çevirir. Bunun yerine, a<b && a>ctarayıcıyı kullanırsanız , işaretlemeyi, a<b && a>c</b>boşluk olmaması <bbir <b>öğeyi açan anlamına geldiği için yorumlar . İşte bahsettiğim şeyin hızlı bir demosu .
zzzzBov

5
Bu muhtemelen gördüğüm en yüksek oyu alan trol cevabı. ;)
aandis

75

Yöntem 1 . Dizenin HTML verisi içerip içermediğini test etmek için basit işlev:

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

Buradaki fikir, tarayıcı DOM ayrıştırıcısının sağlanan dizenin HTML gibi görünüp görünmediğine karar vermesine izin vermektir. Gördüğünüz gibi basitçe ELEMENT_NODE( nodeTypeof 1) için kontrol ediyor .

Birkaç test yaptım ve işe yarıyor gibi görünüyor:

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

Bu çözüm, HTML dizesini doğru bir şekilde algılar, ancak img / vide / etc gibi bir yan etkiye sahiptir. etiketler, innerHTML'de ayrıştırıldıktan sonra kaynakları indirmeye başlayacak.

Yöntem 2 . Başka bir yöntem DOMParser'ı kullanır ve kaynak yükleme yan etkilerine sahip değildir:

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

Notlar:
1. Array.fromES2015 yöntemidir, ile değiştirilebilir [].slice.call(doc.body.childNodes).
2. Aramadaki ok işlevi, somenormal anonim işlevle değiştirilebilir.


3
Bu harika bir fikir. Ancak, bu işlev kapanış etiketini (yani isHTML("</a>") --> false) algılayamadı .
Lewis

9
Harika çözüm! .. Bunun tek olumsuz yan etkisi, eğer html'niz bir image src özniteliği gibi herhangi bir statik kaynak içeriyorsa innerHTML, tarayıcıyı bu kaynakları almaya zorlayacak olmasıdır. :(
Jose Browne

@JoseBrowne, DOM'a eklenmemiş olsa bile?
kuus

1
@kuus Evet, eklemeseniz bile. DOMParser çözümünü kullanın.
dfsq

1
İyi fikir, ama kabul edilen cevap performans için daha iyi olmaz mıydı? Özellikle büyük dizeleriniz varsa (amaçlanan) veya bu testi çok kullanmanız gerekiyorsa.
DerpyNerd

13

Aşağıdakilerle biraz doğrulama:

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

Bu, boş etiketleri (bazıları önceden tanımlanmış) arar ve /XHTML boş etiketlerini sonlandırır ve boş etiket nedeniyle HTML olarak doğrular VEYA etiket adını yakalar ve HTML olarak doğrulamak için dizede bir yerde kapanış etiketini bulmaya çalışır.

Açıklanan demo: http://regex101.com/r/cX0eP2

Güncelleme:

Doğrulamayı şu şekilde tamamlayın:

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

Bu, TÜM HTML etiketlerini içerdiğinden , önce boş olanlar, ardından kapanış etiketi gerektiren geri kalanlar içerdiğinden doğru doğrulama yapar .

Demo burada açıklanmıştır: http://regex101.com/r/pE1mT5


1
Alt normal ifadenin işe yaradığına ancak "'<strong> merhaba dünya" gibi kapatılmamış html etiketlerini algılamayacağına dikkat edin. bu bozuk html olduğu için bir dize olarak değerlendirilmelidir, ancak pratik amaçlar için uygulamanız bunları da algılamak isteyebilir.
TK123

HTML, kullanıcı aracılarının affediciliği düşünülerek tasarlanmıştır. "Geçersiz" etiketler geçersiz değildir, sadece bilinmemektedir ve izin verilmektedir. "Geçersiz" öznitelikler geçersiz değildir… Bu, özellikle "web bileşenlerini" ve JSX gibi HTML ve daha zengin bileşen açıklamalarını karıştıran ve tipik olarak gölge DOM oluşturan teknolojileri içermeye başladığında dikkat çekicidir. Bunu bir dosyaya tokatla ve değerlendir document.querySelector('strange')- işe yarayacak.
amcgregor

(Özetlemek gerekirse: Spesifikasyonun nasıl yazıldığına bağlı olarak, HTML biçimlendirmesini "doğrulamaya" çalışmak aslında aptalca bir iştir. "Geçersiz" bir öğeye sahip örnek bir HTML belgesine verilen bağlantı, burada % 100 tamamen oluşturulmuş, tam HTML belgesi —ve 1997'den beri
amcgregor

10

zzzzBov'un yukarıdaki yanıtı iyidir, ancak örneğin, başıboş kapanış etiketlerini hesaba katmaz:

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

Kapanış etiketlerini de yakalayan bir sürüm şu olabilir:

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

Bunu yorum olarak göndermek yerine bir düzenleme önermek daha iyi olabilirdi.
Zlatin Zlatev

Sanırım <[a-z/][\s\S]*>ilk gruptaki eğik çizgiye dikkat edin.
Ryan Guill

7

İşte zaman zaman kullandığım özensiz bir tek satırlık:

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

Temelde true, <ardından gelen ve ANYTHINGardından gelen dizeler için dönecektir >.

By ANYTHING, boş bir dize dışında temelde hiçbir şey ifade.

Harika değil, ama tek satırlık.

Kullanım

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

Gördüğünüz gibi mükemmel olmaktan uzak, ancak bazı durumlarda işi sizin için yapabilir.


1
tam da ihtiyacım olan şey. Fantezi değil, sadece temiz. Teşekkürler!
moeiscool

6

Buradaki tüm cevaplar fazlasıyla kapsayıcıdır, sadece <ardından ararlar >. Bir dizenin HTML olup olmadığını belirlemenin mükemmel bir yolu yoktur, ancak daha iyisini yapabilirsiniz.

Aşağıda son etiketleri arıyoruz ve çok daha sıkı ve daha doğru olacaktır:

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

Ve işte eylemde:

# 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

Bir dize değişmezinden bir normal ifade oluşturuyorsanız, herhangi bir ters eğik çizgiden kaçınmanız gerekir:

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

Bir normal ifade kullanırsanız bu gerekli değildir, ancak daha sonra eğik çizgilerden kaçmanız gerekir:

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

Ayrıca jsfiddle'ınız çalışmadı çünkü onloadbaşka bir işleyicinin içine bir onloadişleyici atadınız - soldaki Çerçeveler ve Uzantılar panelinde ayarlandığı gibi varsayılan , JS'yi bir onload. Bunu bir nowrap seçeneği olarak değiştirin ve dizge kaçışını düzeltin ve "çalışır" (herkesin yorumlarda belirttiği kısıtlamalar dahilinde): http://jsfiddle.net/wFWtc/4/

Bildiğim kadarıyla JavaScript normal ifadelerinin geriye dönük referansları yoktur. Yani ifadenizin bu kısmı:

</\1>

JS'de çalışmaz (ancak diğer bazı dillerde çalışır).



Bu, etiketlerden birinin iyi göründüğünü test edecek, ancak geri kalanı hakkında hiçbir şey yok. OP'nin ne tür bir "geçerlilik" istediğinden emin değilim.
nhahtdh

1
peki ya <br> <hr> <input...>@ user1240679?
CSᵠ

3

/<\/?[^>]*>/.test(str) Yalnızca html etiketleri içerip içermediğini tespit edin, bir xml olabilir


27 is < 42, and 96 > 42. Bu HTML değil.
amcgregor

3

JQuery ile:

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

2
isHTML("<foo>");// döndürür true isHTML("div");vardır doğruysa // döner divsayfasındaki ler
ACK_stoverflow

@yekta - Ne düşünüyorsun? Bunun, dizenin html olup olmadığını kontrol etmesi gerekir. Bildiğim kadarıyla bir e-posta html etiketi değil ... isHTML ('foo@bar.com ') -> false // true
gtournie

1
Bir dize herhangi bir şey olabilir, eğer onun bir HTML etiketi olduğunu biliyorsanız, o zaman neden ilk başta HTML olup olmadığını kontrol edin, amacınızı tam olarak takip etmiyorum. @Bir seçicinin için geçerli bir sözdizimi değildir. Bir jQuery seçicinin geçmek zaman Böylece, (yani bir özel durum oluşturur $("you@example.com")dan !!$(str)[0]). Özellikle !!$(str)[0] kısmına atıfta bulunuyorum . Cevabınızı az önce düzenlediniz, ancak şimdi jQuery bir şey yapmadan önce HTML'yi kontrol ediyorsunuz.
yekta

Yazarın bunun sadece bir dizi olup olmadığını kontrol etmek istediğini sanmıyorum. Konu bu. İstediği şey, dizenin yalnızca HTML değil, geçerli bir HTML etiketi olup olmadığını kontrol edebilen bir işlevdi (aksi takdirde bu biraz aptalca olurdu ). @ACK_stoverflow yorumunu okuduktan sonra cevabımı güncelledim, ancak eminim basit bir normal ifadenin bunu yapması gerekir.
gtournie

3

Bu durumda jQuery kullanıldığında en basit biçim şu olur:

if ($(testString).length > 0)

Eğer $(testString).length = 1, bu, içinde bir HTML etiketi olduğu anlamına gelir textStging.


Hemen aşağıdaki cevaba göre (bundan dört yıl önce yazılmış olan "jQuery ile" ile başlayarak!), Tek bir giriş noktasından çoklu kullanımların kötü seçimini düşünün. $()bir CSS seçici işlemidir. Ama aynı zamanda metinsel HTML serileştirmeden bir DOM düğüm fabrikası. Ama aynı zamanda… jQuery'ye aynı bağımlılıktan muzdarip diğer yanıta göre, "div" HTML değildir, ancak sayfada trueherhangi bir <div>öğe varsa bu geri döner . Gereksiz yere jQuery içeren hemen hemen her çözümden beklediğim için bu çok, çok kötü bir yaklaşım. (Ölmesine izin ver.)
amcgregor

2

Metni ayrıştırmak için tarayıcının kendisini kullanmayı, herhangi bir DOM düğümünün inşa edilip edilmediğini belirlemeyi içeren, bu da ... yavaş olacak süslü çözümler var. Veya daha hızlı olacak, ancak… potansiyel olarak yanlış olan normal ifadeler. Ayrıca bu sorundan kaynaklanan iki çok farklı soru vardır:

S1: Bir dizge HTML parçaları içeriyor mu?

Dize , HTML öğesi biçimlendirmesi veya kodlanmış varlıklar içeren bir HTML belgesinin parçası mı ? Bu, dizinin ağartma / temizleme veya varlık kod çözme gerektirebileceğinin bir göstergesi olarak kullanılabilir:

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

Görebilirsiniz kullanımda bu deseni bu yazının yazıldığı anda mevcut tüm cevaplar örneklerle tüm karşı, artı bazı ... oldukça çirkin WYSIWYG- veya Word tarafından oluşturulan örnek metin ve karakter varlık referansları çeşitli.

S2: Dize bir HTML belgesi mi?

HTML spesifikasyonu şok edici bir HTML belgesi gördüğü ne olduğu gevşek olduğu . Tarayıcılar, neredeyse her türlü çöp metnini HTML olarak ayrıştırmak için aşırı uzunluklara gider. İki yaklaşım: ya sadece HTML'yi göz önünde bulundurun (çünkü bir text/htmlİçerik Türü ile teslim edilirse , kullanıcı aracısı tarafından HTML olarak yorumlanmaya çalışmak için büyük çaba harcanacaktır ) ya da önek işaretini arayın:

<!DOCTYPE html>

"İyi biçimlilik" açısından, bu ve neredeyse hiçbir şey "gerekli" değildir. Aşağıda, atlandığını düşündüğünüz her HTML öğesini içeren % 100 eksiksiz, tamamen geçerli bir HTML belgesi verilmiştir :

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

Evet. Orada gibi "eksik" elemanlarını oluşturmak için nasıl açık kurallar vardır <html>, <head>ve <body>. SO'nun sözdizimi vurgulamasının, açık bir ipucu olmadan bunu düzgün bir şekilde tespit edememesini oldukça eğlenceli buluyorum.


0

Benim çözümüm

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

Normal ifadeniz çok kusurlu görünüyor vs daha kapsamlı ifade ve ön işleme (başlangıç değiştirme) gerektiren son derece talihsiz bir durumdur.
amcgregor

-1

Bu https://github.com/sindresorhus/is-html'yi çözmeye çalışabilecek bir NPM paketi is-html var


Ben yok kullanımda çalıştığı ifade idrak ilan doctype hariç başarısız ve ek bağımlılık dan çekti bilinen HTML elemanlarından oluşturulmuş "tam" desen HTML nasıl çalıştığını bu değil olmadığı gerçeği göz ardı değil, sahip çok, çok uzun zamandır. Ek olarak, temel desen , her ikisi de tamamen isteğe bağlı olan açıkça belirtilir <html>ve <body>etiketler . "XML eşleşmiyor" testi anlatıyor.
amcgregor

@amcgregor çözümünüzün daha iyi olduğunu düşünüyorsanız, isHTML deposuna katkıda bulunabilirsiniz. ve regex101'deki test grubunuzu eklemek ister misiniz? topluluk için değerli olacaktır
Colin D

Bu kitaplığın temel amacı yanlıştır ve çok sayıda durumda doğası gereği yanlış olacaktır, genellikle anlamadığı etiketlerin varlığından dolayı HTML değil şeklinde yanlış işaretleyerek; doğrulama bu şekilde başarılı olamaz. Ek olarak, basit bir normal ifade veya bir (düzenleme: bir çift ) kitaplık [lar]… nasıl programlanacağını unutmuş olabiliriz ve Düğüm / NPM, genellikle kullanmak, katkıda bulunmak veya kullanımını teşvik etmek istediğim bir dil veya araç zinciri değildir. .
amcgregor

Pekala amcgergor, ben yardım etmeye çalışırken bana oldukça olumsuz davranıyorsun. Npm'nin yanlış yönlendirildiği önermesine katılmıyorum. Yığın taşma cevabınızın gelecekte küçük bir değişiklik ile geldiğini hayal edin. Ben, kütüphanenizi kullanan bir geliştirici olarak, sadece yükseltme yapardım ve daha uygun davranışlar elde ederdim. Bunun yerine, düzenlemelerinizi almak için .... bozuk davranışla yaşamak veya bu yığın taşması yanıtını tekrar gözden geçirmek zorundayım? Alternatif evren budur
Colin D

Olumsuz? Duruşumu ve başka türlü mantıklı görünen bir şeyi neden yapmayacağımı açıklıyordum. Bununla birlikte, bağlantılandırdığım makalenin, bol miktarda tartışma yaratan , biraz daha iltihaplı bir ilk (önden bağlantılı) devamı olduğuna dikkat edin. Yine oraya bağlanan teknik bir makale yayınladı . Yeniden çalışma konusundaki içgüdülerinize kaliteyle ilgili kanıtlarla karşılık veriyorum. Ref: §7.2 (& the left-pad felaket & eslint)
amcgregor
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.