HTML
この記事では、入力値が決めた形式に合っているかを確認するHTMLのpattern属性と、正規表現を使った基本的な検証方法を説明します。
The pattern attribute in the HTML <input> element is a feature that validates whether a user's input matches a pre-defined regular expression pattern.
<input pattern>
Webフォームでユーザーからの入力を制限・検証する方法として、HTMLの<input>要素のpattern属性は非常に便利です。
pattern属性の基本
役割と概要
- 目的
pattern属性は、フォームの送信前にユーザー入力が特定の正規表現パターンに一致するかどうかをチェックします。これにより、入力値の形式(例:メールアドレス、電話番号、郵便番号など)をあらかじめ定義し、不正な入力を防止できます。- 基本の書式
-
HTML
<input type="text" pattern="正規表現"> - ここで「正規表現」は、ユーザー入力が一致すべきパターンを記述した文字列です。
対応する入力タイプ
主にテキスト入力(type="text"、type="search"など)で使用されますが、その他の入力タイプ(例:type="tel"など)でも利用できます。
数値入力(type="number")など一部のタイプでは、組み込みの検証が行われるため、pattern属性は不要な場合があります。
正規表現とpattern属性
正規表現の基本
- 正規表現(Regex)とは
- テキストのパターンマッチングに用いられる記述法で、特定の文字列パターンを定義します。例えば、メールアドレスや電話番号などの形式を指定するのに使用されます。
- HTMLでの注意点
- HTMLの
pattern属性は、JavaScriptなどで使用される正規表現とほぼ同じルールに従って記述されますが、入力値全体がそのパターンにマッチするかどうかを自動的にチェックする仕組みになっています。つまり、正規表現を記述するときに通常使う先頭のアンカー(^)や末尾のアンカー($)は、実際にはHTMLのpattern属性では省略しても、ブラウザ側で入力全体に対してチェックが行われるため、暗黙的に適用されることになります。 - そのため、たとえば末尾の「
$」を明示的に書いても、入力全体がパターンに合致するかどうかは同じ結果となり、省略しても問題ありません。しかし、正規表現の意味や意図をより明確に伝えるために、あえて「$」を記述するケースもあります。これは、パターンの構造を見たときに、どこで文字列の終わりを意図しているのかがはっきりするというメリットがあります。 - 同様に、先頭の「
^」についても、明示的に書くことは可能です。明示することで、パターンの開始位置が文字列の最初であることを示し、意図をより分かりやすくする効果があります。ただし、HTMLのpattern属性では先頭と末尾が自動的にチェック対象になるため、実際の動作としては先頭と末尾のアンカーを省略しても、入力全体がパターンに一致するかどうかの検証結果は変わりません。初心者の方にとっては、これらのアンカーを明示するかどうかは「書くか書かないかのスタイルの違い」であり、どちらを使っても基本的な検証機能に違いはないと理解していただければよいでしょう。 - 例 :
<input type="text" pattern="[A-Za-z]{3,}">は、少なくとも3文字の英字のみの入力を要求します。
実際の例
メールアドレスの入力例
以下は、メールアドレスを正規表現でチェックし、正しければ画面に表示する最もシンプルなサンプルコードです。
HTML
<label for="email">メールアドレス:</label>
<input type="email" id="email" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$" required>
<button onclick="validate()">送信</button>
<p id="result" role="status" aria-live="polite" aria-atomic="true"></p>
<script>
<!-- JavaScript code here -->
</script>
JavaScript
function validate() {
const emailInput = document.getElementById('email');
const email = emailInput.value;
const regex = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/;
const resultEl = document.getElementById('result');
if (regex.test(email)) {
resultEl.textContent = '有効なメールアドレス : ' + email;
} else {
resultEl.textContent = '無効なメールアドレスです。';
}
}
このコードでは、ユーザーがメールアドレスを入力して「送信」ボタンを押すと、JavaScriptのvalidate()関数が呼ばれ、正規表現で入力値を検証し、有効な場合はそのメールアドレスを表示します。
以下の正規表現は、メールアドレスの形式を検証するためのもので、各部分は以下のような意味を持ちます。
HTML
^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$
^- 文字列の先頭を示すアンカー。これにより、先頭からパターンが一致している必要があります。
[a-z0-9._%+-]+- これはメールアドレスの「ローカル部」(
@より前の部分)を表します。 - 含まれる文字は、小文字の英字 (
a-z)、数字 (0-9)、ピリオド (.)、アンダースコア (_)、パーセント (%)、プラス (+)、ハイフン (-)です。 ]の後ろの+は、これら[]内で示した文字が1文字以上連続している必要があることを意味します。@- ローカル部とドメイン部を区切る固定文字「
@」です。 [a-z0-9.-]+- これはメールアドレスの「ドメイン部」(
@の後、トップレベルドメインの直前の部分)を表します。 - 含まれる文字は、小文字の英字 (
a-z)、数字 (0-9)、ピリオド (.)、ハイフン (-)です。 ]の後ろの+は、これら[]内で示した文字が1文字以上連続している必要があることを意味します。\.- エスケープされたピリオド。ドメイン名とトップレベルドメイン(TLD)を区切るための「
.」を表します。 [a-z]{2,}- これはトップレベルドメイン(例: com, net, org など)を表す部分です。
[a-z]は小文字の英字のみを許容し、{2,}は2文字以上でなければならないことを示します。$- 文字列の終端を示すアンカー。これにより、パターンが文字列の最後まで一致する必要があります。
この正規表現全体で、メールアドレスが先頭から末尾まで正確にこのパターンに従っているかをチェックし、不正な形式の入力を防ぐ仕組みとなっています。
電話番号の入力例
以下は、電話番号(例: "090-1234-5678")を正規表現でチェックし、正しければその番号を表示する最もシンプルなサンプルコードです。電話番号の入力には、pattern属性で「2~4桁-2~4桁-3~4桁」の形式を指定しています。
HTML
<label for="phone">電話番号 (例: 090-1234-5678):</label>
<input type="tel" id="phone" name="phone" pattern="\d{2,4}-\d{2,4}-\d{3,4}" required>
<button onclick="validate2()">送信</button>
<p id="result2" role="status" aria-live="polite" aria-atomic="true"></p>
<script>
<!-- JavaScript code here -->
</script>
JavaScript
function validate2() {
const phoneInput = document.getElementById('phone');
const phone = phoneInput.value;
// pattern属性と同じ正規表現をJavaScriptでも使用
const regex = /^\d{2,4}-\d{2,4}-\d{3,4}$/;
const resultEl = document.getElementById('result2');
if (regex.test(phone)) {
resultEl.textContent = '有効な電話番号 : ' + phone;
} else {
resultEl.textContent = '無効な電話番号です。';
}
}
このコードでは、ユーザーが電話番号を入力し「送信」ボタンを押すと、JavaScriptのvalidate2()関数が呼ばれ、入力値が正規表現にマッチしているかをチェックします。正しい形式の場合は画面にその番号が表示され、不正な場合はエラーメッセージが表示されます。
以下の正規表現は、電話番号が「数字(2~4桁)-数字(2~4桁)-数字(3~4桁)」という形式になっているかを検証するためのものです。各部分の意味は以下のとおりです。
HTML
/^\d{2,4}-\d{2,4}-\d{3,4}$/
^- 文字列の先頭を示します。これにより、入力が文字列の最初からパターンに沿っているかをチェックします。
\d{2,4}\dは任意の数字(0〜9)を意味し、{2,4}はその数字が2桁以上4桁以下連続していることを表します。これが最初の数字の部分(例:"090"や"03"など)に対応します。-- ハイフンをそのまま文字として表します。数字の区切りに使われる記号です。
\d{2,4}- 再び、数字が2桁以上4桁以下連続している部分です。これが中間の数字部分に該当します(例:
"1234"や"123"など)。 -- 再度、ハイフンの区切りを示します。
\d{3,4}- 最後の部分では、数字が3桁以上4桁以下連続している必要があることを示します。通常、これが電話番号の末尾の数字部分(例:
"5678"や"678"など)に該当します。 $- 文字列の末尾を示します。これにより、入力がパターンに従い文字列の最後まで一致していることを確認します。
このように、正規表現全体は、入力された電話番号が必ず先頭から末尾まで、指定した「桁数」と「ハイフンによる区切り」を正確に守っているかどうかをチェックします。もしこのパターンに一致すれば、有効な形式と判断され、そうでなければエラーメッセージが表示される仕組みになっています。
応用例と実践的な使い方
ユーザーエクスペリエンス向上のための工夫
エラーメッセージのカスタマイズ
ブラウザが自動で生成するエラーメッセージは十分でない場合があります。title属性を使って、ユーザーに対してどのような入力が期待されているかを明示するとよいでしょう。
HTML
<label for="four-digit-code">4桁の数字:</label>
<input type="text" id="four-digit-code" pattern="\d{4}" title="4桁の数字を入力してください" required>
ここのサンプルではテキストボックスにカーソルを当てるとtitle属性に入力した文字列(4桁の数字を入力してください)が表示されます。
リアルタイムのフィードバック
JavaScriptと組み合わせることで、入力中にフィードバックを表示するなど、ユーザーエクスペリエンスをさらに向上させることが可能です。たとえば、oninputイベントを利用して、入力がパターンに合致しているかを確認し、メッセージを表示するなどの方法があります。
以下は、メールアドレス入力欄でリアルタイムに入力の妥当性をチェックし、フィードバックを表示する最もシンプルなサンプルコードです。
HTML
<label for="email2">メールアドレス:</label>
<input type="email" id="email2" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$" required oninput="checkEmail()">
<p id="feedback" role="status" aria-live="polite" aria-atomic="true"></p>
<script>
<!-- JavaScript code here -->
</script>
JavaScript
function checkEmail() {
const emailInput2 = document.getElementById('email2');
const feedback = document.getElementById('feedback');
// HTMLのバリデーション機能を利用
if (emailInput2.validity.valid) {
feedback.textContent = "正しいメールアドレスです。";
} else {
feedback.textContent = "無効なメールアドレスです。";
}
}
このコードでは、oninputイベントを利用して、ユーザーが入力するたびにcheckEmail()関数が実行され、ブラウザの組み込みバリデーション(validityプロパティ)を使って入力値がパターンに合致しているかをリアルタイムでチェックし、その結果を画面に表示します。
複雑なパターンの構築
グルーピングやオプションの使用
正規表現の高度な機能(グループ化、量指定子、オプションなど)を使うことで、より複雑な入力検証が可能です。
例 : 郵便番号(例: "123-4567" または "1234567" の両方を許可する)
HTML
<input type="text" pattern="\d{3}-?\d{4}" title="郵便番号は「123-4567」または「1234567」の形式で入力してください" required>
ここでの正規表現 \d{3}-?\d{4} は、主に7桁の数字の中で、3桁と4桁の間にハイフンがあってもなくても良いというパターンを表しています。各部分を詳しく解説すると、以下のようになります。
\d{3}\dは数字(0〜9)を意味します。{3}はその数字が「ちょうど3回」繰り返されることを指定しています。- 例 : 「
123」など。 -?- ハイフン(
-)そのものを表します。 ?は直前の文字が「0回または1回」現れることを意味し、ハイフンがあってもなくても良いという条件を示しています。- 例 : 「
-」があっても「1234567」のようにハイフンがなくても良い。 \d{4}- 同様に、
\dは数字を意味し、{4}は「ちょうど4回」数字が連続していることを指定します。 - 例 : 「
4567」など。
この正規表現全体で、「1234567」や「123-4567」のような形式にマッチします。つまり、最初の3桁の数字の後にハイフンが0個または1個あり、続けて4桁の数字が並ぶパターンを検証するために使われます。
否定先読みや条件分岐
これらのテクニックを使うと、特定の条件下でのみ入力を許可する、といった高度な検証が可能になります。ただし、正規表現が複雑になるため、メンテナンス性や可読性を考慮する必要があります。
実例:パスワードの検証
強固なパスワードの例
大文字、小文字、数字、特殊文字を含む8文字以上のパスワードを要求する場合の例です。
HTML
<label for="password">パスワード:</label>
<input type="password" id="password" name="password"
pattern="(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}"
title="パスワードは8文字以上で、大文字、小文字、数字、特殊文字をそれぞれ1文字以上含む必要があります。" required>
ここでの正規表現は、パスワードの強度をチェックするためによく使われるパターンで、以下の条件を全て満たす必要があります。
HTML
(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}
(?=.*[a-z])- 肯定の先読み (Positive Lookahead) を使っています。
.*は任意の文字(改行を除く)が0文字以上続くことを意味します。[a-z]は小文字のアルファベットが少なくとも1文字含まれていることを確認します。- 結果として、この部分は「どこかに小文字が1文字以上存在する」ことをチェックします。
(?=.*[A-Z])- 同じく肯定の先読みを使用し、
[A-Z]により大文字が1文字以上含まれているかを検証します。 - これにより、パスワードに大文字が必ず含まれる必要があります。
(?=.*\d)- こちらも肯定の先読みで、
\dは数字(0〜9)を表します。 - つまり、「数字が1文字以上含まれている」ことを確認しています。
(?=.*[\W_])- これも肯定の先読みです。
\Wは「単語文字(アルファベット、数字、アンダースコア)以外の文字」、つまり記号やスペースなどを意味します。- ただし、アンダースコア(
_)は通常単語文字に含まれるため、ここでは明示的に含めるために[\W_]としています。 - この部分は、「記号またはアンダースコアが1文字以上存在する」ことをチェックします。
.{8,}- ドット(
.)は改行を除く任意の1文字を表します。 {8,}はその直前の要素が8文字以上続く必要があることを意味します。- 結果として、パスワード全体が最低8文字以上でなければならないという条件を表しています。
この正規表現は、「小文字、大文字、数字、記号(またはアンダースコア)の各要素を1つ以上含み、かつ全体で8文字以上の文字列」であることを検証します。これにより、パスワードとして一定以上の強度が求められる条件を満たしているかどうかをチェックすることができます。
肯定の先読み(Positive Lookahead)
正規表現における肯定の先読み(Positive Lookahead)は、ある位置から先に特定のパターンが存在するかどうかを確認するための構文です。具体的には、(?=パターン)という形式で記述され、次のような特徴があります。
- 非消費的検査
- 肯定の先読みは、検査対象のパターンが文字列中に存在するかをチェックしますが、そのパターン自体を「マッチ結果」に含めたり、文字列の位置を進めたりしません。つまり、先読みによって確認された部分はマッチ結果には影響せず、検証だけが行われます。
- 使い方の例
- 例えば、パスワードの強度チェックで「少なくとも1つの小文字が含まれている」ことを確認する場合、
(?=.*[a-z])と記述します。ここで、.*は任意の文字が0文字以上続くことを意味し、その後に[a-z]が来ることで「どこかに小文字が存在する」ことを確認しています。 - 複数の先読みの組み合わせ
- 複数の肯定の先読みを連続して使うことで、同じ文字列に対して複数の条件(例:小文字、大文字、数字、記号など)を同時に検証することが可能です。各先読みは独立してチェックされ、全ての条件が満たされた場合にのみ全体の正規表現がマッチします。
- 実際の動作イメージ
- 文字列「Pass123!」に対して、
(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}という正規表現を適用する場合、 -
(?=.*[a-z])は「a, s, s」などの小文字が存在するかを確認し、(?=.*[A-Z])は「P」の存在を確認し、(?=.*\d)は「1, 2, 3」の存在を確認し、(?=.*[\W_])は「!」が存在するかを確認します。- これらのチェックが全て成功すれば、全体のパターン
.{8,}で8文字以上であることも確認され、マッチと判断されます。
まとめると、肯定の先読みは、正規表現で複数の条件を同時に満たしているかを検証するための強力なツールであり、マッチングの過程で実際の文字列を「消費」せずに条件確認だけを行う点が特徴です。
注意点と制限事項
ブラウザ依存性
各ブラウザの実装
pattern属性はほとんどの最新ブラウザでサポートされていますが、ブラウザごとの実装の差異やユーザー設定により、エラーメッセージの表示や動作が異なる場合があります。
※ そのため、JavaScriptによる補完検証を併用するのが望ましい場合もあります。
ユーザーの利便性とアクセシビリティ
過度な制約の回避
あまりにも厳格なパターンを設定すると、正当な入力まで拒否してしまう可能性があります。ユーザーがどのような入力を行うかを十分に考慮し、柔軟なパターンを設計することが重要です。
視覚的なフィードバック
エラーが発生した際の表示方法を工夫し、スクリーンリーダーなどを利用するユーザーにもわかりやすいエラーメッセージを提供しましょう。
セキュリティとの関係
クライアント側検証の限界
pattern属性による検証はクライアント側で行われるため、セキュリティ対策としては不十分です。必ずサーバー側でも入力の検証とサニタイズを行い、悪意ある入力を防ぐことが必要です。
中・上級者向けのテクニック
複雑なパターンのデバッグ方法
正規表現チェッカーの活用
複雑な正規表現を作成する際は、オンラインの正規表現チェッカー(例:regex101.comなど)を利用して、パターンの動作確認を行うと良いでしょう。これにより、意図しないマッチや漏れを事前に発見できます。
コメント付き正規表現
JavaScriptやサーバーサイドの言語では、正規表現にコメントを入れることができる「拡張モード(xフラグ)」が利用できます。HTMLのpattern属性では直接コメントは使えませんが、ドキュメントやコード内のコメントとして解説を残すと保守性が向上します。
既存のライブラリとの連携
フロントエンドバリデーションライブラリ
jQuery Validation Pluginなどのライブラリは、HTMLのpattern属性による検証と連動して、よりリッチなユーザーインターフェースのフィードバックを提供します。これらを活用することで、エラーメッセージのカスタマイズや、複数項目の同時検証が容易になります。
カスタムバリデーション
HTMLだけでなく、JavaScriptで独自のバリデーションロジックを追加する場合、pattern属性で基本チェックを行い、さらに細かい条件についてはJavaScriptで検証するというハイブリッドなアプローチが効果的です。
まとめ
HTMLの<input pattern>属性は、Webフォームでのユーザー入力のフォーマットを簡単に制限・検証するための強力なツールです。
- 初心者向けには
- 基本的な使い方やシンプルな正規表現の例を学ぶことで、フォームの入力制限の重要性を理解できます。
- 中・上級者向けには
- 複雑な正規表現やJavaScriptとの連携、さらには既存ライブラリとの組み合わせによる実践的なテクニックを習得することで、より堅牢かつユーザーフレンドリーなWebフォームを構築することが可能です。
また、pattern属性によるクライアント側検証はあくまで補助的なものであり、サーバー側での検証との併用が必須です。ユーザーエクスペリエンスとセキュリティの両面から最適なフォーム設計を目指しましょう。