🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

1383閲覧

rails jquery 全角2文字、それ以外半角1文字でカウント

shawn_709

総合スコア13

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2021/01/05 04:28

Twitterのようなアプリを作成しています。
ご回答いただけるとありがたいです。よろしくお願いします!

実現したいこと

ツイート投稿画面で、文字を入力するとそれに合わせて以下の条件で文字数をカウントできるようにしたいです。
全角は2文字分でカウント、他(半角英数字と改行)は1文字分でカウント。

狙い

日本語での投稿量と英語での投稿量を同じぐらいにするためです。メモリの大きさとかを考慮したいわけではありません。あくまで言語が変わっても最大投稿量を同じぐらいにしたいと考えています。

現状

バリデーションの設定で全角2文字、半角英数字と改行は1文字カウントの設定はできています。

model

1#tweet.rb 2class Tweet < ApplicationRecord 3 belongs_to :group 4 belongs_to :user 5 has_one_attached :image 6 7 validates :content, presence: true, unless: :was_attached?, 8 length_with_wide_char: { maximum: 400 } 9 10 def was_attached? 11 self.image.attached? 12 end 13end 14 15#length_with_wide_char_validator.rb 16class LengthWithWideCharValidator < ActiveModel::EachValidator 17 def validate_each(object, attribute, value) 18 value = value.gsub(/\r\n/,"\n") 19 count = 0 20 value.split(//).each do |v| 21 v.bytesize > 1 ? count += 2 : count += 1 22 end 23 object.errors[attribute] << (options[:content] || "is too long (maximum is %d characters)" % options[:maximum]) if count > options[:maximum] 24 end 25end

しかし、現状ではjqueryを用いた目に見える部分での文字数カウントは何を入力しても1文字扱いになっています。
これを全角と半角・改行でカウントを変更したいです。

該当のソースコード

views

1#new.html.erb 2<div class="tweet-form"> 3 <%= form_with model: [@group, @tweet], local: true do |f| %> 4 <div class="tweet-form-container"> 5 <div class="tweet-form-wrapper"> 6 <div class="tweet-form-upper"> 7 <%= f.text_area :content, class: "tweet-form-upper-input input-text", autofocus: true %> 8 </div> 9 <div id="image-list"></div> 10 <div class="tweet-form-lower"> 11 <label class="tweet-form-lower-left"> 12 <div class="tweet-form-lower-left-icon"> 13 <span class="camera-icon"><i class="fa fa-camera-retro fa-fw"></i></span> 14 <%= f.file_field :image, class: 'hidden' %> 15 </div> 16 </label> 17 <div class="tweet-form-right"> 18 <div class="input-text-count"></div> 19 <div class="tweet-form-submit"> 20 <%= f.submit 'ツイート', class: "tweet-form-submit-btn" %> 21 </div> 22 </div> 23 </div> 24 </div> 25 </div> 26 <% end %> 27</div>

js

1#count.js 2if (document.URL.match( "tweets/new" ) || document.URL.match(/groups/\d+/tweets/\d+/edit/)) { 3 $(function (){ 4 var count = $(".input-text").text().length; 5 6 var now_count = 400 - count; 7 8 if (count > 400) { 9 $(".input-text-count").css("color","red"); 10 } 11 $(".input-text-count").text(now_count); 12 13 $(".input-text").on("keyup", function() { 14 var count = $(this).val().length; 15 var now_count = 400 - count; 16 17 if (count > 400) { 18 $(".input-text-count").css("color","red"); 19 } else { 20 $(".input-text-count").css("color","black"); 21 } 22 $(".input-text-count").text(now_count); 23 }); 24 }); 25}

###試したこと・調べたこと(1)
Jqueryで動的に全角改行2文字 半角1文字で文字数カウント
を参考に以下のようにコードを書いてみましたが、全文字1カウントになります。

if (document.URL.match( "tweets/new" ) || document.URL.match(/groups/\d+/tweets/\d+/edit/)) { $(function (){ var result = 0; var count = $(".input-text").text().length; for (var i = 0; i < count ; i++){ var chr = text.charCodeAt(i); if ((chr >= 0x00 && chr < 0x81) || (chr === 0xf8f0) || (chr >= 0xff61 && chr < 0xffa0) || (chr >= 0xf8f1 && chr < 0xf8f4)) { result += 1; } else { result += 2; } } var now_count = 400 - count; if (count > 400) { $(".input-text-count").css("color","red"); } $(".input-text-count").text(now_count); $(".input-text").on("keyup", function() { var count = $(this).val().length; var now_count = 400 - count; if (count > 400) { $(".input-text-count").css("color","red"); } else { $(".input-text-count").css("color","black"); } $(".input-text-count").text(now_count); }); }); }

###試したこと・調べたこと(2)
【jQuery】全角を半角2つとして文字数カウントする
を参考に以下のようなコードを書きました。

if (document.URL.match( "tweets/new" ) || document.URL.match(/groups/\d+/tweets/\d+/edit/)) { $(function(){ $('.input-text').on('keyup', function(){ var len = textLength($(this).val()); $('.input-text-count').text(len); }); }); function textLength(text){ var regexp = /[\x01-\x7E\u{FF65}-\u{FF9F}]/mu; var len = 0; for(i = 0; i < text.length; i++){ var ch = text[i]; len += regexp.test(new String(ch)) ? 1 : 2; } return len; } }

これで全角を2文字、他を1文字カウントをすることができました。
次にカウントダウン形式にしたいので、以下のようにしました。

if (document.URL.match( "tweets/new" ) || document.URL.match(/groups/\d+/tweets/\d+/edit/)) { $(function(){ $('.input-text').on('keyup', function(){ var len = textLength($(this).val()); $('.input-text-count').text(len); }); }); function textLength(text){ var regexp = /[\x01-\x7E\u{FF65}-\u{FF9F}]/mu; var len = 0; for(i = 0; i < text.length; i++){ var ch = text[i]; len += regexp.test(new String(ch)) ? 1 : 2; } var count = $(".input-text").text().length; var now_count = 400 - count; if (count > 400) { $(".input-text-count").css("color","red"); } $(".input-text-count").text(now_count); $(".input-text").on("keyup", function() { var count = $(this).val().length; var now_count = 400 - count; if (count > 400) { $(".input-text-count").css("color","red"); } else { $(".input-text-count").css("color","black"); } $(".input-text-count").text(now_count); }); } }

こうすると全文字1カウントになってしまいます。
カウントダウン方式で全角2文字・他1文字カウントになるようにご助言いただきたいです。

以上になります。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2021/01/05 04:49

jsとrubyどちらでやりたいのでしょうか
shawn_709

2021/01/05 04:51

railsにjqueryを導入して実装を進めています。 (答えになっていなかったらすみません。)
guest

回答1

0

ベストアンサー

こんにちは。
「以下のようにしました」の中で変だなと思うところにコメントを付けてみました。

js

1$(function(){ 2 $('.input-text').on('keyup', function(){ 3 var len = textLength($(this).val()); 4 $('.input-text-count').text(len); 5 }); 6}); 7 8// textLength の戻り値がおかしい 9// 数値を期待しているはず 10function textLength(text){ 11 // textLength の外に書いた方が速そう 12 var regexp = /[\x01-\x7E\u{FF65}-\u{FF9F}]/mu; 13 14 // 計算された len を使っていない 15 var len = 0; 16 for(i = 0; i < text.length; i++){ 17 var ch = text[i]; 18 len += regexp.test(new String(ch)) ? 1 : 2; 19 } 20 21 // ここから .css() や .text() で書き換えてますが 22 // textLength ではテキストの長さの計算だけしましょう 23 var count = $(".input-text").text().length; 24 // len ではなく count を引いている 25 var now_count = 400 - count; 26 // 色の設定(重複) 27 if (count > 400) { 28 $(".input-text-count").css("color","red"); 29 } 30 // カウントの設定(重複) 31 $(".input-text-count").text(now_count); 32 33 // textLength() が呼ばれるたびに keyup イベントが登録されている 34 $(".input-text").on("keyup", function() { 35 var count = $(this).val().length; 36 var now_count = 400 - count; 37 // 色の設定(重複) 38 if (count > 400) { 39 $(".input-text-count").css("color","red"); 40 } else { 41 $(".input-text-count").css("color","black"); 42 } 43 // カウントの設定(重複) 44 $(".input-text-count").text(now_count); 45 }); 46}

修正したのは以下です。
https://jsfiddle.net/fntwzjv2/

投稿2021/01/05 06:31

編集2021/01/05 06:34
neko_daisuki

総合スコア2090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問