JS:テキストボックスの文字数を得る

テキストボックスの文字数を得るの画像JavaScript
スポンサーリンク

時々(ほんとうに時々ですが)自分で書いた文章が何文字あるのかを知りたいときがあります。
JavaScriptで簡単にできるのでは?と思い作成してみました。

単純にテキストボックスに入力した文字数を知りたい方は以下のリンクからどうぞ。

テキストボックスの文字数を得る

JavaScriptを使ってどうやって作るのかを知りたい方は、以下の長い文章をご覧ください。

JavaScriptでは文字列(Stringオブジェクトとも言う)に含まれる改行文字(\n)などは、1文字扱いになるのでチェックボックスを使って文字数から省く機能をつけました。
日本語だと半角スペース全角スペース混同の文章がありますので、こちらもチェックボックスを使って文字数から省く機能をつけました。

スポンサーリンク

大まかなイメージ

ファイルは、index.html(ユーザインターフェース)、main.js(プログラム)、style.css(レイアウト、見た目)からなっています。

テキストボックスへの入力を検知し、リアルタイムで文字数を表示する、という処理をします。

画面イメージです。
テキストボックスの文字列を得るの実行画面の画像

index.htmlは、ユーザインターフェース部分です。

入力部分
テキストボックス(文字入力用)
チェックボックス3つ(改行をはぶく、半角スペースをはぶく、全角スペースをはぶく)

出力部分
文字数表示

main.jsは、主にキー入力イベントに対する処理です。3つのチェックボックスがどれがチェックされているかによって表示される文字数が変わってきます。

style.cssでは、画面サイズによって見やすくなるようレイアウトをしています。
ポイントを1つだけあげるとしたらチェックボックスの配置をフレックスボックスを使ってレイアウトしていることです。
これにより、横長の場合は、3つのチェックボックスが均等な位置関係で表示され、

横長
テキストボックスの文字列を得るの実行画面の画像
サイズを縦長にしてもチェックボックスのレイアウトが自然にきまります。

縦長
テキストボックスの文字列を得るの実行画面の画像
フレックスボックスは、レイアウトがかなり楽になりますよ。フレックスボックスに関しては、後程説明しています。

ユーザインターフェース部分(HTML)

スタイルシートは、style.cssに記述します。

<link rel="stylesheet" href="style.css">

文字数をカウントするプログラムは、main.jsに記述します。

<script type="text/javascript" src="main.js"></script>

HTMLファイルでは、文字数表示用のpタグ(id名textLength)、文字入力用にtextareaタグ(id名textBox)を1つ、チェックボックス用にinputタグ(id名withoutCR, withoutSpace, withoutByteSpace)を3つ作成しています。

HTML部分の全体

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<link rel="stylesheet" href="style.css">
	<title>テキストボックスの文字数を得る</title>
	<meta name="viewport" content="width=device-width">
	<script type="text/javascript" src="main.js"></script>
</head>
<body>
	<header>
		<h1>テキストボックスの文字数を得る</h1>
	</header>

	<div id="contents">
		<p id="textLength">0</p>
		<textarea id="textBox" placeholder="文字を入力してください..."></textarea>
		<div id="flex-container">
			<div class="item"><label><input id="withoutCR" type="checkbox">改行をはぶく</label></div>
			<div class="item"><label><input id="withoutSpace" type="checkbox">半角スペースをはぶく</label></div>
			<div class="item"><label><input id="withoutByteSpace" type="checkbox">全角スペースをはぶく</label></div>
		</div>
	</div>

	<footer>
		<p>&copy; 2018 <a target="_blank" href="https://dianxnao.com/">dianxnao.com</a></p>
	</footer>
</body>
</html>

inputタグをlabelタグの中に入れているのは、意味があります。
こうすることでチェックボックスをクリックしても改行をはぶくなどの対応する文字列をクリックしてもチェックボックスが反応するようになります。

<label><input id="withoutCR" type="checkbox">改行をはぶく</label>

使い勝手に影響する部分なので大事な作りだと思います。

改行をはぶく考え方(JavaScript)

JavaScriptで文字列変数に設定した文字数を得るには、lengthプロパティを利用すれば簡単です。

var str = "Hello!";
console.log(str.length);

しかし、テキストボックス内の文字列の場合、複数行にわたる文字列だと改行文字も1文字とカウントされてしまいます。
テキストボックスの文字列を得る改行はぶかない場合の画像

そこでStringクラスreplaceメソッドを使って改行をすべて空欄(””と置換することで結果的に消去になる)に置換します。
置換した後のlengthプロパティを取得すれば、改行をはぶいた場合の文字数になります。

replaceメソッドの使い方

str = str.replace( 検索文字列, 置き換える文字列 );

改行は、\nで表されます。通常のreplaceメソッドの書き方であれば

textValue = textValue.replace("\n", "");	// 先頭の改行のみ置換
console.log(textValue.length);	// 文字数を表示

などとなりますが、これだと最初に登場する改行1文字しか置き換えてくれません。

こういう場合は、正規表現を使います。

textValue = textValue.replace(/\n/g, "");	// 改行を全て置換
console.log(textValue.length);

置き換えたい文字を/(半角スラッシュ)でくくります。
/の後にgとついているのは、「出現する全ての」という意味になるので、この場合文字列内に出現するすべての改行を空欄に置き換えて(消去して)くれます。

半角スペースや全角スペースも考え方は同様です。

半角

textValue = textValue.replace(/ /g, "");

全角

textValue = textValue.replace(/ /g, "");

正規表現は、文字列からパターンを見つけてそれらを特殊文字で表現する考え方です。何言っているか分からないっす!という方は今回の方法だけでも憶えておくと便利に使えますよ。
正規表現は、それだけで1冊の本になってしまうので、今回は、この辺にしておきます。

詳しくは、

MDN – 正規表現

をご覧ください。眠くなります(笑)

キーボードイベントに対応させる(JavaScript)

JavaScriptでのキーボードイベント3つあります。
イベントの発火(イベントが起きるタイミング)順に記述すると以下のようになります。

keydownそのキーを押した瞬間に発生
keypresskeydownで押されたキーが修飾キー(Ctrl, Shift, Alt等)でなかったとき発生
keyupキーボードを押して離した瞬間に発生

詳しくは以下のMDNのサイト(補足部分)に記述されています。

KeyboardEvent – MDN

ただし、上記のサイトでも記述されているとおり、keydownkeypressタイミングは、ブラウザによっても違うとのことですのでご自分で確認することをおすすめします。
今回の処理では、一番自然な動作をしていたkeyupイベントで処理することにしました。

イベントの設定にはaddEventListenerを使います。
例えばサイト上でどんなキーが押されたか判断する場合は、addEventListenerを使って以下のように記述します。

document.addEventListener("keydown", (event) => {
	const keyName = event.key;
	alert(keyName + "が押された");
}, false);

引数に指定したeventとプロパティkeyを使ってどんなキーが押されたかを取得できます。
他にもシフトキーやAltキーなどの判断もプロパティshiftKeyやaltKeyなどで可能です。その際は、true/falseが戻り値として返ります。

今回の処理では、テキストボックスでの入力イベントのみを判断しているためkeyプロパティは使っていません。
例えばid名textBoxで指定したタグのkeyupイベントの処理関数keyHandlerに設定する場合は、以下のようにします。

textBox = document.getElementById("textBox");	// テキストボックスのDOM取得
textBox.addEventListener("keyup", keyHandler, false);	// keyupイベントの処理を設定

これでキーを離したときに、関数keyHandlerの処理が実行されます。

addEventListenerの第3引数は、trueにするとそのタグの親タグで発生したイベントも処理するようになります。falseにしておいた方が使いやすいと思います。

上記の記述はここ最近推奨されているイベントの記述方法です。(2018年時点)
keyupの頭ににonをつけて以下のように記述しても可能です。

textBox = document.getElementById("textBox");	// テキストボックスのDOM取得
textBox.onkeyup = keyHandler;	// keyupイベントの処理を設定

=による代入形式でのイベント記述になるので、同じイベントに複数の関数の処理を実行させたいときは上書きされてしまいます。この場合、最後に代入したイベントが設定されます。
addEventListenerだと複数の処理を同じイベントに追加できる点で有利です。

【追記 2019-09-30】
自分で使用していて気づいたのですが、テキストボックスに文字列をCtrl + Vで貼り付けたときは文字数がカウントされるのに対し、マウス右クリック+貼り付けを選んだときは、文字数のカウントがされないことに気づきました。

原因はマウス右クリックによる貼り付けに対応できていなかったためです。
よって、イベント処理部分に以下を追加しました。

textBox.addEventListener("paste", function(){			// テキストボックス内で貼り付けをしたとき
	setTimeout(keyHandler, 100);						//	Ctrl+V, マウス右クリック+貼り付け双方に対応
}, false);

ちなみにpasteイベントは、キーボード・マウス双方の貼り付けに対応する便利なイベントです。

ここまで改行をはぶく部分キーイベント処理について解説してきました。
JavaScript部分の全体は以下の通りです。

/* main.js */

var textBox = null;			// テキストボックス
var textLength = null;		// テキストボックス内の文字数表示部分
var withoutCR = null;			// チェックボックス - 改行をはぶく
var withoutSpace = null;		// チェックボックス - 半角スペースをはぶく
var withoutByteSpace = null;	// チェックボックス - 全角スペースをはぶく

/*
 * keyHandler: テキストボックス内の文字を表示する関数
 */
function keyHandler(){
	// テキストボックスの文字列を取得
	let textValue = textBox.value;

	// チェックボックスの状態を取得
	let noCR = withoutCR.checked;
	let noSpace = withoutSpace.checked;
	let noByteSpace = withoutByteSpace.checked;

	// チェックボックスの状態によって数え方を変える
	if(noCR){
		textValue = textValue.replace(/\n/g, "");	// 改行をはぶく
	}
	if(noSpace){
		textValue = textValue.replace(/ /g, "");	// 半角スペースをはぶく
	}
	if(noByteSpace){
		textValue = textValue.replace(/ /g, "");	// 全角スペースをはぶく
	}
	
	// 文字数を取得して表示
	let n = textValue.length;
	textLength.innerHTML = n + " 文字";
}

/*
 * 起動時の処理
 */
window.onload = function(){
	// DOM取得
	textBox = document.getElementById("textBox");						// テキストボックス
	textLength = document.getElementById("textLength");					// 文字数表示部分
	withoutCR = document.getElementById("withoutCR");					// チェックボックス(改行をはぶく)
	withoutSpace = document.getElementById("withoutSpace");			// チェックボックス(半角スペースをはぶく)
	withoutByteSpace = document.getElementById("withoutByteSpace");	// チェックボックス(全角スペースをはぶく)
	
 	// イベント設定(いずれのイベントもkeyHandlerを呼び出して文字表示を行っている)
	textBox.addEventListener("keyup", keyHandler, false);	// テキストボックス内でキーを離したとき
	textBox.addEventListener("paste", function(){			// テキストボックス内で貼り付けをしたとき
		setTimeout(keyHandler, 100);						//	Ctrl+V, マウス右クリック+貼り付け双方に対応
	}, false);
	withoutCR.addEventListener("click", keyHandler, false);	// チェックボックスをクリックしたとき
	withoutSpace.addEventListener("click", keyHandler, false);
	withoutByteSpace.addEventListener("click", keyHandler, false);

	// テキストボックスの文字数を表示
	keyHandler();
}

フレックスボックスで3つのチェックボックスをレイアウト(css)

見た目がどうでも良ければ以上でおわりなのですが、せっかくWebアプリとして作るのであればレイアウトにもこだわりたいです。

style.cssでフレックスボックスを使ったレイアウトをしています。

HTML部分で、3つのチェックボックスをdivタグid名flex-containerでくくりました。
先ほど説明したlabelタグinputタグごとdivタグクラス名itemでくくっている点に注目してください。
フレックスボックスを使ったレイアウトは、レイアウト範囲をid付きのdivタグでくくって、レイアウトしたいものを、クラス名(itemなどとすると分かりやすい)をつけたdivタグでくくることが基本です。

今回は、レイアウト範囲をdiv id=”flex-container”とし、レイアウトしたいアイテムをdiv class=”item”としました。

<div id="flex-container">
	<div class="item"><label><input id="withoutCR" type="checkbox">改行をはぶく</label></div>
	<div class="item"><label><input id="withoutSpace" type="checkbox">半角スペースをはぶく</label></div>
	<div class="item"><label><input id="withoutByteSpace" type="checkbox">全角スペースをはぶく</label></div>
</div>

これをスタイルシートを適用せずに表示すると

テキストボックスの文字数を得るフレックスボックスを使わない場合の画像

このように縦にレイアウトされます。
ここでフレックスボックスの出番です。

style.cssでは、以下のようにしました。

/* フレックスボックス(チェックボタン部分) */
div#flex-container{	/* コンテナー部分 */
	display: flex;		/* 横並びにする */
	flex-wrap: wrap;	/* コンテナ内のアイテムを折り返して表示 */
	justify-content: space-between;	/* 等間隔に並べる */
}

displayプロパティをflexにするだけでアイテムが横並びになります。
flex-wrapプロパティをwrapとすると、画面サイズに対応して自然に折り返すようになります。
justify-contentプロパティは、等間隔に並べるためにspace-betweenを指定しています。他にも中央揃えにするcenterなどもあります。

フレックスボックスの書き方は以下のリンクが分かりやすかったです。

日本語対応!CSS Flexboxのチートシートを作ったので配布します – Webクリエイターボックス

ぜひ参考にしてみてください。

今回のソースコード全体

最後にコード全体を示します。
読んで頂きありがとうございました。

コメント