質問: JavaでHTMLタグの開始タグ・終了タグのバリデーションチェックをしたいのですが、正規表現を理解したいです。 ``` (<(\\s*(?:/\\s*)?【tag name】(?:\\s*|\\s+[^>]+))(?:>|(?=<)|$(?!\\n))) ``` こちらでタグチェックをしている参考箇所を見つけたのですが、正規表現でどういう意味なのでしょうか? 自分でも分析していますが、なかなか理解にたどり着けません。もしアドバイスいただける方がいればよろしくお願いいたします。 --- 追記 自分なりに解析してみています。アドバイスいただけたら幸いです。 1 **(**<(\s*(?:/\s*)?【tag name】(?:\s*|\s+[^>]+)**)** **(**?:>|(?=<)|$(?!\n))**)** この太字カッコは「グループ化」でしょうか?ここをまず優先的に処理する。前タグ()のタグ名(a)前後を分けているのでしょうか? 2 **\\s***は「空白0個以上」でしょうか? 3 (?:/\\s*) ここがよくわかりません。。 「:が1個以上でしょうか?」ただタグで:があるケースってあるのかな。。 そして「/が必要」でしょうか?あとは「空白0個以上」でしょうか? 4 カッコのあとの?はなんでしょうか?【tag name】の前の?です 5 **(**?:\s*|\s+[^>]+**)** この太字カッコは「グループ化」でしょうか? 6 ?: 「コロン1文字」でしょうか?コロンがよくわからない。。 7 \s*は「空白が0文字以上」でしょうか? 8 |で前後いずれかの文字。`?:\\s*`か`\\s+[^>]+` 9 \s+で「空白1個以上」でしょうか? 7 [^>]+で「>以外の文字1個以上」でしょうか? 8 **(**?:>|(?=<)|$(?!\n)**)** 太字カッコの部分がグループ化でしょうか? 9 ?:コロン1文字でしょうか? 10 >で「>が必要」ということでしょうか? 11 ?:>|(?=<)|$(?!\n) このパイプで「?:>」か「(?=<)」か「$(?!\n)」でしょうか? それ以降のところもご指導いただけるとありがたいです。
回答: まず、あなたが記載された正規表現は、Javaの文字列リテラル中に埋め込まれた形になっているようです。Javaで文字列リテラル`"\\"`は、`\`の1文字を表していることは既にご理解いただいているものとしますが、`\`は、ここスタック・オーバーフローで使われているMarkdown記法でも意味を持つので、あなたの質問文中では`\\s`と表示されたり`\s`と表示されたりが混在しています。 以下の説明では、 * 文字列リテラル中の表記であることを示すために必ず両側に`"`を付加しています (幸い今回の正規表現中には`"`は現れないので混乱はしにくいかと思っています。) * 文字そのものを表す部分はコード用のスタイルにせず太字にもしていません * メタ文字(文字そのもの以外を表す記号)はコード用スタイルにして太字にしています ご質問の正規表現を上記のルールで整形しなおすと、こんな感じになります。 `"`**`(`**<**`(\\s*(?:`**/**`\\s*)?`**【tag name】**`(?:\\s*|\\s+[^`**>**`]+))(?:`**>**`|(?=`**<**`)|$(?!\\n)))`**`"` (変なところに隙間が空いてしまいますが、意図的な空白は置いていません。) あなたが使われているブラウザで読みやすく表示されていれば良いのですが、文字そのものを表しているのは、< / > の3種類の文字しかありません。 それ以外の文字は全てメタ文字で、何らかの意味を表しています。Javaの正規表現中で使える全てのメタ文字については、Javaの公式ドキュメントに出てきています。(ただし、どこをどう取ってもわかりやすいとは言えないので、「わからん!」と思ってもあなたのせいではありません。他の解説記事と併用して読んでください。またJavaのバージョンにより若干変化があるかもしれません。) `Pattern` (Java platform SE 8 ) その中から、ご質問の正規表現に使われているものを先の規則に当てはめて整形しながら列挙していきます。 `"`**`(`***X***`)`**`"` *X*、前方参照を行う正規表現グループ `"`**`\\s`**`"` 空白文字: `[\t\n\x0B\f\r]` `"`*X***`*`**`"` *X*、0回以上 `"`**`(?:`***X***`)`**`"` *X*、前方参照を行わない正規表現グループ `"`*X***`?`**`"` *X*、1または0回 `"`*X***`|`***Y*`"` *X* または *Y* `"`*X***`+`**`"` *X*、1回以上 `"`**`[^`** abc **`]`**`"` a、b、c以外の文字(否定) `"`**`(?=`***X***`)`**`"` *X*、幅ゼロの肯定先読み `"`**`$`**`"` 行の末尾 `"`**`(?!`***X***`)`**`"` *X*、幅ゼロの否定先読み `"`**`\\n`**`"` 改行文字(「`\u000A`」) * 「前方参照」については、「キャプチャ」と言う言葉を使っている解説記事が多いようです。 * 「幅ゼロの」「先読み」については、マッチするかどうかチェックするがチェック位置は進めないと言うことです。「正規表現 肯定先読み」なんかで検索すると、読みやすく書かれた解説記事が見つかると思います。 追記の1〜11については、**`(?:`** 〜 **`)`** を括弧と`?:`とに分けて解釈しようとしているのを修正すれば、ほぼ理解されているようですので、個別には触れません。この回答(やリンク先)を読んでみて、まだわからないことがあれば、コメント等でお知らせください。