textarea とか input など、入力欄を使っているとバイト数で入力文字数を制限したい時があります。
ただ実際にコードを書いて試してみると、これが中々面倒くさかったです。
そこで自分の記憶の整理も兼ね、textareaなどで入力をバイト数で制限する方法をまとめました。
入力をバイト数で制限できる方法を考えてみる
まずバイト数制限できる textarea とか input を作るための実装方法について考えてみます。
「単に文字数がバイト数に変わるだけだから簡単そう」と思いがちですが、実は色々考えないといけないことがあって結構厄介です。
まず課題となるのは 文字をどうやってバイト数でカウントするか について
そのためには次の2点を考慮しないといけません。
- 半角と全角が混在すること
- 全角は2バイトとは限らないこと
当然、半角と全角が混じるので 1文字 = 1バイト みたいな数え方はできないです。
あと気を付けないといけないのは日本語1文字は必ず2バイトとは限らないことですね。
Shif-JIS とか EUC-JP とかだったら全角1文字 = 2バイト みたいに決まってるんですが、UTF-8だと1文字3バイトだったり、稀に4バイトになることもあります。
そして、次の課題は 入力文字を実際に制限するコードの書き方 について
もし指定のバイト数に達したら textarea 側で次の処理を行わないといけません。
- キーボードからの入力を止める
- IMEからの入力・確定も止める
- クリップボードから貼り付けできなくする
- テキストをドロップさせないようにする
普通にキーボード入力だけ制限だと、貼り付けとかドラッグ&ドロップで入力ができてしまいます。
厳密にバイト数で制限するには「入力欄の内容が変わるイベントを全て監視して適切な処理をする必要がある」という所が結構難しいところですね。
バイト数で入力制限できる textarea のコード例
ということで上記2点を意識して実際にバイト数制限できる textarea を実装してみました。
そのコードとバイト数制限できる textarea の作り方は次の通りです。
まず次のように文字列をバイト数に変換できる関数を作成
1 2 3 4 |
/* 文字列をバイト数で返す関数 */ $.getByteLength = function(value){ return encodeURIComponent(value).replace(/%../g,'x').length; }; |
やっていることは文字列をURI形式(
%E3%81%82 みたいなやつ )にエンコードし、
正規表現で
%xx の数(すなわちバイト数)を取得しているだけです。
ちなみに今回は $.getByteLength みたいにjQuery関数として登録してますが、別に独立した関数として書いても問題ありません。単にjQuery側で扱いやすいように、こう書いてるだけです。
そして上の関数を作ったら、肝心なイベント処理部分を書いていきます。
今回は textarea と input[type="text"] でバイト数制限できるコードを書いてみました。
その具体的なコード例は次の通り
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
$('textarea.limit-byte-length, input[type="text"].limit-byte-length') .on('keypress compositionend paste drop', function(e){ var MAX_BLEN = $(this).attr('maxbytelength'); var value = $(this).val(); var valueByteLen = $.getByteLength(value); if(valueByteLen > MAX_BLEN){ switch(e.type){ case 'compositionend': /// IMEでの入力が確定したとき var imeData = e.originalEvent.data; $(this).val(value.substr(0, value.length - imeData.length)); break; } } switch(e.type){ case 'keypress': /// 半角文字が入力されたとき if($.getByteLength(e.key)==1 && valueByteLen+1 > MAX_BLEN) e.preventDefault(); e.stopPropagation(); break; case 'paste': /// 貼り付けが反映される前 var pasted = (window.clipboardData && window.clipboardData.getData) ? window.clipboardData.getData('Text') : e.originalEvent.clipboardData.getData('text/plain'); var futureByteLen = valueByteLen + $.getByteLength(pasted); if(futureByteLen > MAX_BLEN){ e.preventDefault(); e.stopPropagation(); } break; case 'drop': /// ドロップが反映される前 var dropped = e.originalEvent.dataTransfer.getData("text/plain"); var futureByteLen = valueByteLen + $.getByteLength(dropped); if(futureByteLen > MAX_BLEN){ e.preventDefault(); e.stopPropagation(); } break; } }); |
先ほど説明したみたいに各イベント(入力とか貼り付け、ドロップ)が起きた時に、指定バイト数以上にならないようにイベントを無効化したり、テキストの書き換えを行っているだけです。
このコードを追加すると limit-byte-length というクラス名を持つ入力欄に maxbytelnegth 属性が指定されているときだけ、そのバイト数で入力が制限されるようになります。
つまり1000バイトで入力制限したいなら次の textarea タグを定義すればOK
1 2 3 |
<!-- テキストエリアを1000バイトで制限 --> <textarea class="limit-byte-length" maxbytelength="1000"></textare> |
ちなみに普通の入力欄で制限する場合も次みたいに同様の書き方ができます。
1 2 3 |
<!-- 入力欄を1000バイトで制限 --> <input type="text" class="limit-byte-length" maxbytelength="1000" /> |
ここでは textarea と input[type="text"] だけバイト数制限できるようにしましたが、jQueryコードのセレクタ部分を変えれば他の入力形式の要素にも対応できるようになります。
ここまでのまとめ
入力欄でバイト数制限する方法とコード例は以上の通り
完璧に全ての入力をチェックしたわけではないので、もし何か不備を発見した場合はコメントで指摘していただけるとありがたいです。
以上、textareaなどの入力欄でバイト数制限する方法についてでした。ではでは($・・)/~~~