dポイントプレゼントキャンペーン実施中!

テキストエリアの文字を1行ごとにカウントさせたいのです。
現在は半角なら0.5、全角なら1.0としてカウントさせて、これを行ごとに分散させたいのです。

未達の条件
・改行、スペースはカウントしない
・各行ごとのカウントになっていない

<!doctype html>
<html>
<head>
<meta charset="euc-jp">
<title>テキストエリアの文字カウント</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1 …
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1 …
<script>

function ShowLength( str ) {
len = 0;
for(i=0;i<str.length;i++) {
var c = str.charCodeAt(i);

if ( (c >= 0x0 && c < 0x81) || (c == 0xf8f0) || (c >= 0xff61 && c < 0xffa0) || (c >= 0xf8f1 && c < 0xf8f4)){
len += 0.5;
}
else { len += 1; }
}
len = parseFloat(len).toFixed(1)
document.getElementById("inputlength01").innerHTML = len;
document.getElementById("inputlength02").innerHTML = len;
document.getElementById("inputlength03").innerHTML = len;
}
</script>
</head>
<body>
<table>
<tr>
<th>行別カウンター</th>
<td>
<textarea id="input_text" placeholder="" name="summary" rows="5" onkeyup="ShowLength(value,'inputlength');"></textarea>
<div class="countWrrap">
<div class="countDsign">
<ul>
<li id="comment01">1行目: <span id="inputlength01">0.0 </span>/ 35</li>
<li id="comment02">2行目: <span id="inputlength02">0.0 </span>/ 35</li>
<li id="comment03">3行目: <span id="inputlength03">0.0 </span>/ 35</li>
</ul>
</div>
</div>
</td>
</tr>
</table>
</body>
</html>

質問者からの補足コメント

  • うーん・・・

    fujillin さま
    アドバイスありがとうございます。
    とりあえずご指摘を頂きました箇所を修正しました。
    現状では、行ごとに配列化して、それぞれの文字をカウント、指定の位置に表示させることができました。ですが、今度は、半角と全角がそれぞれ1文字ずつのカウントになってしまったようで判定の処理がスルーされてしまっているようです。

    以下変更箇所の抜粋

    function ShowLength( str ) {
    var len = 0;
    //分割処理
    var arr = str.split(/\r\n|\r|\n/);
    for(i=0;i<arr.length;i++){
    }
    //

    ("inputlength01").innerHTML = len;
    を以下の形式に変更
    ("inputlength01").innerHTML = arr[0].length;

    No.1の回答に寄せられた補足コメントです。 補足日時:2017/09/20 18:34

A 回答 (2件)

ANo1です。



う~~~ん・・・

・・とりあえず、
>useNum = str.split(/\r\n|\r|\n/);//これが機能していない感じ
直後にuseNumの内容を調べてみれば、きちんと機能していることがわかると思います。
useNum(=配列)には改行で分割された1行ずつの文字列が取得できます。
通常は、str.split("\n") でも大丈夫だと思いますが、正規表現でもちゃんと動作します。
しかしながら、そのあとの文字チェックのループではもとの全文(str)を対象にループさせているので、なんのために1行ずつに分けたのわかりませんね。

さらには、そのループの中で
>var useNum = new Array();
>useNum.push(len);
としているので、変数宣言に関しては巻き上げられますが、useNum = new Array()の部分は実行されます。
結局、1文字チェックする毎にuseNumを初期化して、それに変数lenをpushしていることになります。
そのあとで、(多分デバッグ用に?)
>console.log(useNum);
となさっていますが、useNumの値は予定通りの内容になっていますか?
この結果、最初に1行ずつに分けたuseNumの内容はすぐに破棄されるので、意味のない処理をしていることになりませんか?

>ShowLength.innerHTML = len.toFixed(1);
ShowLengthは実行中の関数名のはずですが、関数のinnerHTML属性にlen.toFixedの値を代入してどうしようというお考えでしょうか?
(javascriptでは関数もオブジェクトなので、処理自体はエラーにはなりませんが…)

>~~~.innerHTML = useNum[0];
>~~~.innerHTML = useNum[1];
ループの計算でuseNumは初期化されているので、1要素の配列になっているはずです。
また、この値は最後にチェックしたlenの値が入っているはずですが、これを表示したいわけではないと思いますが?
さらに、useNum[1]、 useNum[2]は存在しないので、常にundefinedが出力されるものと想像します。

その他に、
>str = str.replace(/\r\n|\n|\r/g, "");//改行削除
ループ内で毎回処理をしていますが、1度行えばよい処理のはずですので、効率を考えればループの外で処理すべきではないでしょうか?
というよりも、本来なら
>useNum = str.split(/\r\n|\r|\n/)
ですでに改行は取り除かれている文字列を処理するはずなので、不要な処理とも言えます。

HTMLを見てみると、table表示にしていますが、1行2セルのみの構成で、ほとんどの内容が後のセル内にありますが、tableにする意味があるのか疑問です。


などなど、他にもありそうですが・・・
1行ずつ分割したなら、その各行に対して「質問者様がなさりたい文字数計算」を行って、結果をそれぞれの表示用要素に表示するようになさりたいのではないでしょうか?
処理の流れを、もう一度きちんと整理なさってからスクリプトを記述なさった方が良いかもしれません。
また、前回も指摘しましたが、3行決め打ちのスクリプトにしてしまうと、1行しかない時や4行以上ある時に予想外の結果となることがありますので、注意なさった方がよさそうに思います。


なんとなく、なさりたいことが見えてきましたので、似たようなものを作成してみました。
と言っても、全体的に構成をだいぶ変えてしまいましたので、あくまでもご参考としてのものです。
3行までを限定として処理しています。(4行目以降は、存在しても無視)
なお、(どこかに書いてあったように思いますが)スペースの削除はしていません。

<!DOCTYPE HTML>
<html lang="ja">
<head><title>Sample</title>

<style type="text/css">
h4 { display: inline-block; }
span.length { margin: 0 0.5em; }
#countWrap { margin-left: 6em; }
</style>

</head>
<body>

<div>
<h4>行別カウンター</h4>
<textarea id="input_text" name="summary" rows="5"></textarea>
</div>

<ul id="countWrap">
<li>1行目:<span class="length">0.0</span>/ 35</li>
<li>2行目:<span class="length">0.0</span>/ 35</li>
<li>3行目:<span class="length">0.0</span>/ 35</li>
</ul>


<script type="text/javascript">

function C(c, c1, c2){ return c >= c1 && c < c2; }

function codeCheck(c){
return C(c,0x0,0x81) || C(c,0xff61,0xffa0) || C(c,0xf8f1,0xf8f4) || (c==0xf8f0);
}

function countLength(s){
var i, len = 0;
for (i=0; i<s.length; i++){ len += codeCheck(s.charCodeAt(i))?1:2; }
return (len/2).toFixed(1);
}


document.getElementById("input_text").addEventListener("keyup", function(){
var i, strs = this.value.split("\n");
var elms = document.querySelectorAll("#countWrap span.length");
for(i=0; i<3; i++){
elms[i].innerHTML = countLength(strs[i] || "");
}
}, false);

</script>
</body>
</html>
    • good
    • 0
この回答へのお礼

コードのサンプルまで用意していただきましてありがとうございます。

まさに理想としていた動きを確認できました!
加えて、多岐にわたるご指摘を頂きまして今後の励みにもなります。

重ねてお礼申し上げます。

お礼日時:2017/09/22 14:29

こんにちは



なんだかいろいろありそうですが・・・

文字コードの判定部分の内容は確認していませんが、とりあえず一番の原因はループ内で
 len = parseFloat(len).toFixed(1)
としていることではないでしょうか。(文末のセミコロンはここだけ省略?)

toFixedで返される値は文字列になりますので、次回のループで
 len += 0.5;(またはlen += 1;)とする際には文字列連結の演算になります。
https://developer.mozilla.org/ja/docs/Web/JavaSc …
このため、数値の加算にはならないので、思うような結果にならないものと推測します。

表示を必ず少数以下一桁としたいのであれば、変数lenは数値のままとして、表示するときだけ文字列変換を行えばよろしいかと。
具体的には、
 len = parseFloat(len).toFixed(1) を削除し、表示の際に
 element.innerHTML = len.toFixed(1);
などとするとかでしょう。

その他に気が付いたのは、
・jQueryを読み込んでいるけれど、実際には使用していない。
・ShowLength(str)は1引数として定義されているが、HTML内の呼出しでは引数が2つ
・関数呼出しのShowLength(value)の引数Valueはthis.valueなどとしておく方がよさそう。


>未達の条件
>・改行、スペースはカウントしない
>・各行ごとのカウントになっていない
文字列全体をいきなり1文字ずつ解析するのではなく、まず改行コード(\n)で分割して、それぞれの行について解析するようにすれば良いのではないでしょうか。
https://developer.mozilla.org/ja/docs/Web/JavaSc …
(4行以上入力されている場合の処置もお忘れなく)

スペースをカウントしたくないのであれば、解析前にスペースを削除しておけば良いでしょう。
https://developer.mozilla.org/ja/docs/Web/JavaSc …
この回答への補足あり
    • good
    • 0
この回答へのお礼

fujillin さま
アドバイスありがとうございます。
とりあえずご指摘を頂きました箇所を修正しました。
現状では、行ごとに配列化して、0.5単位での加算まで再現できています。
あとは、これを行別に表示させたいのですが、1行目に全ての加算値が表示されてしまいます。


<script>
function ShowLength( str ) {
var len = 0;
useNum = str.split(/\r\n|\r|\n/);//これが機能していない感じ
//文字サイズのチェック
for(i=0;i<str.length;i++) {
str = str.replace(/\r\n|\n|\r/g, "");//改行削除
var c = str.charCodeAt(i);

if ( (c >= 0x0 && c < 0x81) || (c == 0xf8f0) || (c >= 0xff61 && c < 0xffa0) || (c >= 0xf8f1 && c < 0xf8f4)){
len += 0.5;
}
else { len += 1; }

var useNum = new Array();
useNum.push(len);
console.log(useNum);

}

ShowLength.innerHTML = len.toFixed(1);

document.getElementById("inputlength01").innerHTML = useNum[0];
document.getElementById("inputlength02").innerHTML = useNum[1];
document.getElementById("inputlength03").innerHTML = useNum[2];
}

</script>

お礼日時:2017/09/21 10:14

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!