#061
posted on 2021.12.10 (Fri) 2022.09.22 (Thu)

フォームのフィールドに入力された内容を正規表現でバリデーション。

フォームのフィールドに入力された内容を、JavaScriptの正規表現を使って色々な条件判定でバリデーションする方法のメモ。

  1. 入力が空(未入力)ではないかのチェック。
  2. 入力が空白文字(スペース)のみではないかのチェック。
  3. 入力が数字のみになっているかのチェック。
  4. 文字数制限をしたときの入力文字数のチェック。

  5. メールアドレスの形式が正しいかのチェック。
  6. URLの形式が正しいかのチェック。

※ クライアントサイドのバリデーションにセキュリティーの意味は無いので、ユーザーの入力ミスを防止する程度の確認。

※ エラーチェックしてからエラーメッセージを表示させる方法は前の記事(ネイティブJavaScript版jQuery版)を参照。

 

 

フィールドに入力された内容を取得

HTMLフォームのフィールドに入力された内容を取得する作業。

 

HTMLでのフォームの記述。

<form action="送信先URL" method="送信メソッド">
	<input id="field" type="text" name="txt" placeholder="テキスト">
	<button type="submit">送信</button>
</form>

idを「field」としたinput要素に入力されている内容をJavaScriptで取得。

const fieldValue = document.getElementById('field').value;

document.getElementById(‘ID’) : 指定されたIDに一致する要素を表すElementオブジェクトを返す。無ければ「null」を返す。

input要素.value : input要素を操作するためのHTMLInputElementインターフェイスのプロパティー。value属性の値を返す。任意の値を代入して設定することもできる。

 

 

正規表現でバリデーション

取得した値(上記で「fieldValue」に代入した値)を正規表現でチェックする。

 

 

1. 入力が空(未入力)ではないかのチェック

「fieldValue」の値が空(「’empty’」)ではないかを調べる。

※ 「’empty’」の場合は「false」判定になり、「false」の「!」(論理否定)で「true」になった場合だけ処理される。

if(!fieldValue){
	//エラー判定のときの処理
}

 

 

2. 入力が空白文字(スペース)のみではないかのチェック

空白以外の文字が存在するかを正規表現で調べる。(存在しなければ空白文字のみなのでエラーにする。)

const ag2regExp = /[^\s]/;
if(!fieldValue.match(ag2regExp)){
	//エラー判定のときの処理
}

/正規表現パターン/フラグ : 正規表現オブジェクトnew RegExp()と同じ。JavaScriptでリテラルに宣言する場合には、「/」をデリミタに使う。

[^] : 角括弧内で^の後ろに指定している文字以外にマッチ。

\s : [ \t\f\r\n]と同じ。垂直タブ以外のすべての空白文字にマッチ。

対象文字列.match(‘正規表現リテラルまたはRegExpオブジェクト’) : 対象文字列内にマッチする文字列があれば、その文字列を返す。無ければnullを返す。

 

 

3. 入力が数字のみになっているかのチェック

半角数字と全角数字以外の文字が存在するか正規表現で調べる。(数字以外があればエラーにする。)

const ag2regExp = /[^0-90-9]/;
if(fieldValue.match(ag2regExp)){
	//エラー判定のときの処理
}

/正規表現パターン/フラグ : 正規表現オブジェクトnew RegExp()と同じ。JavaScriptでリテラルに宣言する場合には、「/」をデリミタに使う。

[^] : 角括弧内で^の後ろに指定している文字以外にマッチ。

: 角括弧内でのみ使用できる範囲を指定するメタ文字。

対象文字列.match(‘正規表現リテラルまたはRegExpオブジェクト’) : 対象文字列内にマッチする文字列があれば、その文字列を返す。無ければnullを返す。

 

 

4. 文字数制限をしたときの入力文字数のチェック

厳密な文字数の確認が不要なら、JavaScriptでstring(文字列)が持つ「length」プロパティーで判定する。

※ string(文字列)のlengthプロパティーでの文字数確認は正確ではない。

 

[ lengthプロパティーでのカウント ]

  • JavaScriptで文字列の内部処理はUFT-16で実行される。
  • string(文字列)のlengthプロパティーは、UTF-16での文字コード(「コードユニット」)の数でカウントされる。
  • 通常、全角でも半角でも「コードユニット」は1つなので1文字ごとに1でカウントされる。
  • 「サロゲートペア」という絵文字(「😸」など)や異体文字(「𠮷」など)を表す特殊な文字コードが存在し、UTF-16では2つの「コードユニット」の組み合わせで構成されるので、1文字が2とカウントされる。

※ サロゲートペアにも対応した厳格な文字数のチェックをするには対処が必要。

※ サロゲートペアを入力禁止にするにしても、サロゲートペアが含まれているかのチェックが必要。

 

[ サロゲートペアに関する要約 ]

  • すべての文字に振られている固有IDを、Unicodeでは「Code Point」、16ビット(2バイト)の符号単位で表現するUTF-16では「Code Unit」と呼ぶ。
  • Unicodeの未使用領域に新たに加えられた「サロゲートペア」と呼ばれる文字は16ビットを超えているので、UTF-16では2つの「Code Unit」の組み合わせ(32ビット)で表現する。
  • 「サロゲートペア」に使う領域には文字が割り振られていないので他の文字との重複はない。
  • UTF-16で利用される「サロゲートペア」の「Code Unit」は、ハイサロゲート(前半2バイト)とローサロゲート(後半2バイト)からそれぞれひとつずつの組み合わせ(計4バイト)で構成される。
  • UTF-16で利用される「サロゲートペア」の「Code Unit」の領域。
    ハイサロゲート : \uD800 ~ \uDBFF
    ローサロゲート : \uDC00 ~ \uDFFF
  • 文字列中にハイサロゲートとローサロゲートの「Code Unit」が並んだ場合に、1文字(Unicodeでの「Code Point」)として扱われる。

サロゲートペア(代用対)は16ビットUnicodeの領域1024文字分を2つ使い(前半 U+D800 〜 U+DBFF、後半 U+DC00 〜 U+DFFF)、各々1個ずつからなるペアで1024 × 1024 = 1,048,576文字を表す。これはちょうど16面分であり、第1面〜第16面(U+010000 〜 U+10FFFF)の文字をこれで表すこととした。加えて第0面(基本多言語面)も使用可能なので、Unicodeには合計で 1,048,576 + 65,536 – 2,048 = 111万2,064文字分の空間が確保されたことになる。Unicodeの符号空間が10FFFF16まで(サロゲート領域を除いて111万2064文字)とされているのはUTF-16が表現可能な限界だからである。(Wikipedia)

 

当初基本多言語面は以下のような4つの「領域」に分けられていた。

・0000 33FFをアルファベット及び音節文字の用字並びに種々の記号のために使うA領域
・3400 9FFFを中国、日本及び韓国の統合された漢字のために使うI領域
・A000 DFFFを将来の標準化のために使うO領域
・E000 FFFDを私用文字、互換文字と特殊文字の為に使うR領域

しかしながら上記のように例外的な配置が増えてきたため現在基本多言語面で「領域」として定められているのは以下の二つだけである。

・D800 DFFFを代用符号位置に使用するS領域
・E000 F8FFを私用領域

(Wikipedia)

 

U+D800 ~ U+DBFF と U+DC00 ~ U+DFFF の2,048個の符号位置は文字ではなく、サロゲートペア(代用対)に使う代用符号位置(Surrogate Code Point)となっている。上位側の表現に使う U+D800 ~ U+DBFF をHigh-Surrogate Code Point、下位側の表現に使う U+DC00 ~ U+DFFF をLow-Surrogate Code Pointと言う。(weblio辞書)

 

[ 方法(1) 入力された文字数が10文字以下になっているかチェックするエラー判定の方法 ]

JavaScriptの正規表現で、「サロゲートペア」に対応した「コードユニット」の数を調べて、厳密な文字数を判定する。

  1. UFT-16での文字列の内容を正規表現で調べる。(JavaScriptの内部処理はUFT-16なので自動的にエンコードされている。)
  2. 正規表現でコードユニットのエスケープシーケンスを使い、「サロゲートペアに該当する2組のコードユニットの文字列」と「サロゲートペア以外のコードユニットの文字列」を順番に調べる。(マッチするものがひとつも無ければ「null」が返る。)
  3. 「サロゲートペアに該当する2組のコードユニット」か「サロゲートペア以外のコードユニット」にマッチしたら順番に取得して配列として保持。
  4. 取得した配列の要素数が、「サロゲートペア」と「サロゲートペア以外のコードユニット」の合計数になるので、入力された本来の文字数が得られる。
  5. 調べた数が「null」か「10」より多ければエラー判定にする。

※ 文字数の判定以外にも、入力された文字からすべての「サロゲートペア」を抽出できるように関数を作成。(サロゲートペアの入力があればエラー判定にして表示する場合など必要に応じて利用。)

//文字列内のサロゲートペアをチェックする関数
const ag2stringCheck = {
	//サロゲートペアに対応した文字数を保持
	num: function(str){
		//サロゲートペアの文字またはサロゲートペア以外の文字にマッチしたら順番に配列化
		let result = str.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g);
		//配列の要素数を取得
		if(result) result = result.length;
		//結果を返す
		return result;
	},
	//サロゲートペアの文字だけを配列にして保持
	Surrogates: function(str){
		//サロゲートペアの文字にマッチしたら順番に配列化
		return str.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
	}
};

const valiNum = 10;//入力フィールドで指定した制限文字数
if(ag2stringCheck.num(fieldValue) === null || ag2stringCheck.num(fieldValue) > valiNum){
	//エラー判定のときの処理
}

対象文字列.match(‘正規表現リテラルまたはRegExpオブジェクト’) : 対象文字列内にマッチする文字列があれば、その文字列を返す。無ければnullを返す。

/正規表現パターン/フラグ : 正規表現オブジェクトnew RegExp()と同じ。JavaScriptでリテラルに宣言する場合には、「/」をデリミタに使う。

[] : 角括弧に含まれるいずれか1文字にマッチ。角括弧内で使用できるメタ文字(「-」「^」「\」「]」)はエスケープが必要。

: 角括弧内でのみ使用できる範囲を指定するメタ文字。

| : 左右辺の文字列のいずれかにマッチ。

[^] : 角括弧内で^の後ろに指定している文字以外にマッチ。

g : (global)フラグ。正規表現全体に一致したすべての結果を返し、キャプチャグループは返さない。(2番目、3番目…以降にマッチする部分も検索して配列として返す。) gフラグが無かった場合、最初に完全に一致したものと、そのキャプチャグループを返す。

文字列.lenght : stringインスタンスの読み取り専用データプロパティー。指定された文字列のUTF-16でのCode Unitの数を返す。

配列.lenght : Array型のインスタンスであるオブジェクトのプロパティー。配列の要素数を返す、または数値を代入して要素数を設定する。

 

[ 方法(2) 簡単な文字数の確認方法 ] (サロゲートペアを抽出しない方法)

「サロゲートペア」に対応した文字数のチェックをするが、「サロゲートペア」の抽出は不要な場合の確認方法。

  1. 文字列を配列に変換。(文字列のlengthプロパティーでは「コードユニット」の数になってしまうので。)
  2. できた配列の要素数をlengthプロパティーで確認。(「コードユニット」ではなく1文字ずつ配列化されている。)

※ 文字列(Stringオブジェクト)は、反復可能(iterable)、かつ、配列ライク(array-like)なのでArray.from()メソッドでArrayインスタンスを生成できる。

※ Array.from()メソッドは、反復可能なオブジェクトと配列ライクなオブジェクトのどちらにも使用できる。

//文字列内のサロゲートペアをチェックする関数
const ag2stringCheck = {
	num: function(str){
		let result = null;
		//文字列を配列に変換
		let charas = Array.from(str);
		//配列の要素数を取得
		if(charas) result = charas.length;
		//結果を返す
		return result;
	}
};

const valiNum = 10;//入力フィールドで指定した制限文字数
if(ag2stringCheck.num(fieldValue) === null || ag2stringCheck.num(fieldValue) > valiNum){
	//エラー判定のときの処理
}

Array.from(‘オブジェクト’) : 指定した配列風オブジェクトまたは反復可能オブジェクトからArrayインスタンスを生成。

 

[ 方法(3) スプレッド演算子を使った文字数の確認方法 ]

「…」(スプレッド演算子)を使えば、Array.from()メソッドを利用した方法と同じような処理ができるがIEが非対応。

※ ブラウザ対応状況はcan i use参照。

※ 「…」(スプレッド演算子)は、内部的にはfor-of文と同じ方法で文字列から要素として文字を1つずつ集めて配列にしている。

※ 「スプレッド構文」は、反復可能(iterable)なオブジェクトにのみ使用できる。

//スプレッド構文でサロゲートペアに対応した文字数を返す関数
const ag2stringCheck = {
	num: function(str){
		let result = [...str];
		if(result) result = result.length;
		return result;
	}
};

//文字数を表示
console.log(ag2stringCheck.num(fieldValue));

…反復可能オブジェクト : スプレッド構文。配列式や文字列などの反復可能オブジェクトを、記述した場所で展開する。

 

 

5. メールアドレスの形式が正しいかのチェック

メールアドレスの基本構造(「ローカル部」+「@」+「ドメイン」)で構成されているかを正規表現で調べる。

※ 使用可能な文字や形式などは通信キャリアや送信システムで異なり、メールアドレスのフォーマットを規定している文書のRFC 5321やRFC 5322も改訂されることがあるようなので、あまり厳格にチェックしない方が無難。

 

[ 入力されたメールアドレスの構造を正規表現でチェックしてエラー判定 ]

入力された文字列が、「半角英数字か記号が1文字以上」+「@」+「半角英数字か_.-が1文字以上」+「.」+「半角英数字か_-が1文字以上」の構造になっているか正規表現で調べる。(構造がマッチしなければエラーにする。)

const ag2regExp = /^[\w.\-!#$%&'*+/=?\^_`{|}~(),:;<>@[\]"\\]+@[\w.\-]+\.[\w\-]+$/;
if(!fieldValue.match(ag2regExp)){
	//エラー判定のときの処理
}

/正規表現パターン/フラグ : 正規表現オブジェクトnew RegExp()と同じ。JavaScriptでリテラルに宣言する場合には、「/」をデリミタに使う。

^ : 直後に指定した文字が行の先頭にある場合にマッチ。

[] : 角括弧に含まれるいずれか1文字にマッチ。角括弧内で使用できるメタ文字(「-」「^」「\」「]」)はエスケープが必要。

\w : [a-zA-Z_0-9]と同じ。すべての半角英数字とアンダーバーにマッチ。

+ : 直前の指定が1回以上繰り返す場合にマッチ。

$ : 直前に指定した文字が行の末尾にある場合にマッチ。

対象文字列.match(‘正規表現リテラルまたはRegExpオブジェクト’) : 対象文字列内にマッチする文字列があれば、その文字列を返す。無ければnullを返す。

 

 

6. URLの形式が正しいかのチェック

入力された文字列が、「httpsかhttp」+「://」+「任意の1文字以上」+「.」+「任意の1文字以上」の構造になっているか正規表現で調べる。(構造がマッチしなければエラーにする。)

※ 日本語URLなどもあるのですべての文字を入力可能として判定する。

const ag2regExp = /^https?:\/\/.+\..+$/;
if(!fieldValue.match(g2regExp)){
	//エラー判定のときの処理
}

/正規表現パターン/フラグ : 正規表現オブジェクトnew RegExp()と同じ。JavaScriptでリテラルに宣言する場合には、「/」をデリミタに使う。

^ : 直後に指定した文字が行の先頭にある場合にマッチ。

? : 直前の文字が0個か1個の場合にマッチ。

. : 任意の1文字にマッチ。

+ : 直前の指定が1回以上繰り返す場合にマッチ。

$ : 直前に指定した文字が行の末尾にある場合にマッチ。

対象文字列.match(‘正規表現リテラルまたはRegExpオブジェクト’) : 対象文字列内にマッチする文字列があれば、その文字列を返す。無ければnullを返す。

 

 

この記事のURL

https://memo.ag2works.tokyo/post-3233/

Copyコピー
この記事のタイトル

フォームのフィールドに入力された内容を正規表現でバリデーション。 | memo メモ [AG2WORKS]

Copyコピー
この記事のリンクタグ

<a href="https://memo.ag2works.tokyo/post-3233/" target="_blank" rel="noopener">フォームのフィールドに入力された内容を正規表現でバリデーション。 | memo メモ [AG2WORKS]</a>

Copyコピー
※ フィールドをクリックでコピーするテキストの編集ができます。

この記事へのコメント

コメントの書き込みはまだありません。

  • コメント内のタグはエスケープ処理され、文字列として出力されます。
  • セキュリティーのため、投稿者のIPアドレスは取得されます。
  • 管理者が内容を不適切と判断したコメントは削除されます。
  • このフォームにはスパム対策として、Googleの提供するreCAPTCHAシステムが導入されています。
    (Google Privacy Policy and Terms of Service.)