文字列がhtmlかどうかを確認します


98

HTMLかどうかを確認する特定の文字列があります。私は同じために正規表現を使用していますが、適切な結果が得られません。

私は正規表現を検証しましたが、ここでは問題なく動作します

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

ここにフィドルがありますが、正規表現はそこで実行されていません。http://jsfiddle.net/wFWtc/

私のマシンではコードは正常に実行されますが、結果としてtrueではなくfalseが表示されます。ここで何が欠けていますか?


5
HTMLパーサーを使用してHTMLを解析します。まだお読みになっていない場合は、こちらをお読みください。
フレデリックハミディ2013年

3
質問は今後も続きます。htmlとregexを含むすべての質問にコメントを自動的に設定するスタックボットがあるはずです
Bartlomiej Lewandowski 2013

2
これは、チェックにどの程度の洗練度を求めるかによって異なります。あなたは、文字列が少なくとも1含まれているかどうかを確認でき<、かつ少なくとも一つ>とHTMLそれを呼び出す、またはあなたはそれが正しいHTML構文、または間から何かを厳密に有効であることを確認できました。最も単純なケースでは、HTMLパーサーは必要ありません。
JJJ 2013年

2
文字列がHTMLであることを確認する理由
nhahtdh 2013年

2
@ user1240679:有効なマークアップ形式?どのような有効性ですか?厳密に言うと、それを記述するためにDTDが必要です。大まかに言うと、タグが適切に一致していることを確認する必要があります。上記の2つのケースのどちらも、正規表現の仕事ではありません。
nhahtdh 2013年

回答:


314

文字列が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 2013年

7
@clenemt、あなたはa < b && a > cHTMLであると考えていますか?
zzzzBov 2015

1
@zzzzBovあなたはあなたa<b && a>cがHTMLであると考えていることを知っています... HTMLの検出がそれほど単純化されればいいのですが。解析は決して簡単ではありません。
oriadam

2
@oriadam、コンテキストはその場合の要素を検出するためのものでした。a < b && a > cブラウザを使用すると、>および<文字が&gt;および&lt;エンティティに適切に変換されます。代わりに、a<b && a>cブラウザを使用するa<b && a>c</b>と、スペースがないと要素<bが開かれるため、マークアップが解釈され<b>ます。これが私が話していることの簡単なデモです
zzzzBov 2016年

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などの副作用があります。タグは、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、ブラウザがそれらのリソースのフェッチを強制的に開始することです。:(
ホセ・ブラウン14

@JoseBrowneがDOMに追加されていなくても?
kuus '29年

1
@kuusはい、追加しなくてもかまいません。DOMParserソリューションを使用します。
dfsq 2017年

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) 

ALLが含まれているため、これは適切な検証を行います HTMLタグます。最初に空のタグがあり、その後に終了タグが必要な残りのタグが続きます。

ここで説明されたデモ:http : //regex101.com/r/pE1mT5


1
下部の正規表現は機能しますが、「 '<strong> hello world」などの閉じられていないhtmlタグは検出されません。これは壊れたhtmlであるため、文字列として処理する必要がありますが、実際にはアプリでもこれらを検出する必要があります。
TK123 2016

HTMLは、ユーザーエージェントの許しを念頭に置いて設計されています。「無効な」タグは無効ではなく、単に不明であり、許可されています。「無効な」属性は無効ではありません…これは、「Webコンポーネント」や、HTMLとより豊富なコンポーネントの説明を組み合わせ、通常はシャドウDOMを生成するJSXのようなテクノロジーを使用し始めたときに特に顕著です。スラップこれをファイルし、evalの中にdocument.querySelector('strange')それがうまくいきます- 。
amcgregor

(要約すると、仕様がどのように記述されているかにより、HTMLマークアップを「検証」しようとすることは、基本的には愚か者の用事です。「無効な」要素を持つサンプルHTMLドキュメントへのリンクは、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 2016

私はあなたが意味を考える<[a-z/][\s\S]*>-第1グループのスラッシュに注意してください。
ライアンギル2017年

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 2017

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 ------------------------^

また、onload別のハンドラー内にハンドラーを割り当てたため、jsfiddleが機能しませんでしonloadonload。左側の[フレームワークと拡張機能]パネルで設定されているデフォルトでは、JSをでラップしています。これをnowrapオプションに変更し、文字列リテラルがエスケープするのを修正すると、「機能する」(誰もがコメントで指摘した制約内で):http : //jsfiddle.net/wFWtc/4/

私の知る限り、JavaScriptの正規表現には後方参照がありません。だからあなたの表現のこの部分:

</\1>

JSでは機能しません(他の言語では機能します)。



まあ、これはタグの1つがOKに見えることをテストしますが、残りについては何もしません。OPがどのような「有効性」を望んでいるかはわかりません。
nhahtdh 2013年

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")から!!$(str)[0])。私は特にその!!$(str)[0] 部分について言及しています。回答を編集しましたが、jQueryが何かを行う前にHTMLをチェックしています。
yekta 2016年

筆者が文字列であるかどうかを確認したいとは思わない。それがポイントです。彼が欲しかったのは、文字列がHTML だけでなく、有効なHTML タグであるかどうかをチェックできる関数です(そうでなければ、これは少し愚かです)。@ACK_stoverflowコメントを読んだ後、回答を更新しましたが、簡単な正規表現でそれを実行できるはずです。
gtournie 2016年

3

この場合にjQueryを使用すると、最も簡単な形式は次のようになります。

if ($(testString).length > 0)

の場合$(testString).length = 1、これは内部にHTMLタグが1つあることを意味しますtextStging


すぐ下の回答(「jQuery」で始まり、これより4年前に書かれています!)のように、単一のエントリポイントから複数の用途を選択することはよくありません。 $()CSSセレクター操作です。しかし、テキストによるHTMLシリアライゼーションからのDOMノードファクトリも。しかし、また、jQueryへの同じ依存に悩まされている他の回答のように、「div」はHTMLではありませんが、ページに要素が存在するtrue場合に返さ<div>れます。これは、jQueryを不必要に伴うほとんどすべてのソリューションで期待できるようになったので、非常に悪いアプローチです。(死にましょう)
amcgregor

1

ブラウザ自体を使用してテキストを解析し、DOMノードが構築されているかどうかを特定するという、凝った解決策があります。または、正規表現は高速になりますが、…不正確になる可能性があります。この問題から生じる2つの非常に異なる質問もあります。

Q1:文字列にはHTMLフラグメントが含まれていますか?

文字列は、HTML要素のマークアップまたはエンコードされたエンティティを含むHTMLドキュメントの一部ですか?これは、文字列がブリーチ/サニタイズまたはエンティティのデコードを必要とする可能性があることを示すインジケータとして使用できます。

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

このパターンが使用されているのがわかります、この記事の執筆時点では、既存のすべての回答からのすべての例に加え、いくつか...むしろ恐ろしいWYSIWYG-またはWordで生成されたサンプルテキストと文字実体参照の多様性に対する。

Q2:文字列はHTMLドキュメントですか?

HTMLの仕様では、衝撃的な、それがHTMLドキュメントを考えるものへと緩んでいます。ブラウザーは極端な長さで、ほとんどすべての不要なテキストをHTMLとして解析します。2つのアプローチ:すべてのHTMLを考慮する(text/htmlContent-Typeで配信された場合、ユーザーエージェントがHTMLとして解釈しようとするために多大な労力が費やされるため)または接頭辞マーカーを探す:

<!DOCTYPE html>

「整形式」という点では、それだけで、他にほとんど何も「必要」ではありません。以下は、省略されていると思われるすべてのHTML要素を含む100%完全で完全に有効な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からあなたのテストスイートを追加しますか?それはコミュニティにとって価値があります
コリンD

そのライブラリーの基本的な目的は誤っており、多くの場合本質的に間違っています。通常は、理解できないタグが存在するために、HTML以外として誤ってフラグが立てられるためです。検証はこの方法では成功しません。さらに、単純な正規表現または(編集:ペアの)librar [ies]… プログラミング方法を忘れた可能性があり、Node / NPMは、一般的に利用したい、貢献したい、または使用を奨励したい言語またはツールチェーンではありません。 。
amcgregor

申し訳ありませんが、私が手助けしようとしていたとき、あなたは私に対してかなり否定的です。私はnpmが誤解されているという前提に同意しません。スタックオーバーフローの答えが将来的に少し調整されると想像してください。私は、あなたのライブラリを使用する開発者として、アップグレードするだけで、より適切な動作が得られます。代わりに、私は....壊れた動作に耐えるか、このスタックオーバーフローの回答に再度アクセスして編集を行う必要がありますか?それがオルタナティブユニバースです
コリンD

負?私は自分のスタンスを説明していましたが、それが理にかなっていると思われることをしない理由を説明していました。ただし、私がリンクした記事は、わずかに炎症性のある最初の記事(最初にリンクされた記事)からの続きであり、多くの議論を引き起こしたことに注意してください。彼はまた、そこにリンクされているテクニカルペーパーを下に向けて発行しました。品質についての証拠を用いて、あなたのやり直しに対するあなたの直感を打ち消します。参照:§7.2(および左側の災害とeslint)
amcgregor
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.