RubyのString#lengthとbytesizeの違いを徹底解説!文字数カウントの落とし穴とUTF-8対応
生徒
「先生、Rubyで文字列の長さを数えるときにlengthとbytesizeってありますけど、どっちを使えばいいんですか?」
先生
「とても良い質問ですね。String#lengthとString#bytesizeは似ていますが、実は“数えているもの”が全く違うんです。」
生徒
「えっ、違うんですか?どっちも文字の長さを数えているんじゃないんですか?」
先生
「実はlengthは“文字数”を、bytesizeは“バイト数”を数えるんです。日本語のようなマルチバイト文字を扱うときに大きな違いが出てくるので、しっかり覚えておきましょう!」
1. Rubyの文字列とエンコーディングの関係
Rubyの文字列(String)は、単なる文字の集まりではなく、「どのような文字コードで表現されているか(エンコーディング)」という情報も持っています。エンコーディングとは、「文字をデジタルデータ(バイト列)としてどう保存するか」というルールのことです。
たとえば、日本語の「こんにちは」はUTF-8という文字コードでは1文字あたり3バイトで表現されます。つまり、見た目は5文字でも、実際には15バイトのデータになるのです。
このように「文字数」と「バイト数」は異なる概念なので、lengthとbytesizeでは結果が変わることがあります。
2. String#lengthとは?(文字数を数えるメソッド)
String#lengthは「文字列の中に何文字あるか」を数えます。日本語のようにマルチバイト文字でも、見た目の通り1文字としてカウントされます。
text = "こんにちは"
puts text.length
5
このように、「こんにちは」は5文字なのでlengthの結果は「5」です。英数字やひらがな、漢字など、文字の種類に関係なく“目に見える文字の数”を数えます。
3. String#bytesizeとは?(バイト数を数えるメソッド)
String#bytesizeは「その文字列をバイト列にしたときの長さ」を返します。つまり、文字ではなく「データの容量」を数えているのです。
text = "こんにちは"
puts text.bytesize
15
UTF-8では日本語の1文字は3バイトなので、「こんにちは」は5文字×3バイト=15バイトとなります。これがbytesizeの結果です。
たとえば、ファイルサイズの計算やネットワーク通信で送るデータの容量を知りたいときにはbytesizeを使うのが正解です。
4. lengthとbytesizeの違いを比較しよう
ここで英語の文字列と日本語の文字列を比べてみましょう。英語(ASCII文字)は1文字=1バイトですが、日本語(UTF-8)は1文字=3バイトになることが多いです。
english = "Hello"
japanese = "こんにちは"
puts english.length # => 5
puts english.bytesize # => 5
puts japanese.length # => 5
puts japanese.bytesize # => 15
5
5
5
15
この結果から、同じ「5文字」でも、英語は5バイト、日本語は15バイトになります。つまり、「見た目の文字数」と「内部のデータサイズ」は必ずしも一致しません。
5. UTF-8とShift_JISで結果が違う!
Rubyは文字列ごとにエンコーディングを持っているため、同じ文字でもエンコーディングによってbytesizeの結果が変わります。Shift_JISでは1文字=2バイトなので、UTF-8と比較すると結果が異なります。
text = "あいう"
puts text.bytesize # UTF-8: 9バイト
puts text.encode("Shift_JIS").bytesize # Shift_JIS: 6バイト
9
6
このように、文字コードを変えるとデータサイズも変わります。特にファイル入出力や外部APIとの通信では、文字化けの原因にもなるので注意が必要です。
6. 文字数カウントの落とし穴と注意点
初心者がよくやってしまうのが、「文字数を調べたいのにbytesizeを使ってしまう」パターンです。すると、日本語を含む文字列で予想外の値が返ってきます。
たとえば、「Twitterの投稿文字数」や「入力フォームのバリデーション(文字数制限)」を作るときに、bytesizeで判定してしまうと誤差が出ることがあります。
反対に、「データの転送量」や「ファイルの保存サイズ」を知りたいときにlengthを使っても正しい結果にはなりません。
つまり、用途に応じて正しいメソッドを選ぶことが大切です。
7. 実践:文字数とバイト数を両方チェックするサンプル
最後に、文字数とバイト数を同時にチェックするプログラムを作ってみましょう。UTF-8環境での違いがよく分かります。
def check_string_info(str)
puts "文字列: #{str}"
puts "文字数(length): #{str.length}"
puts "バイト数(bytesize): #{str.bytesize}"
puts "エンコーディング: #{str.encoding}"
end
check_string_info("Hello")
check_string_info("こんにちは")
文字列: Hello
文字数(length): 5
バイト数(bytesize): 5
エンコーディング: UTF-8
文字列: こんにちは
文字数(length): 5
バイト数(bytesize): 15
エンコーディング: UTF-8
このように、同じUTF-8でも日本語と英語でバイト数が異なります。Rubyの文字列操作を正しく理解するためには、「文字数」と「バイト数」の違いを意識することが大切です。
8. lengthとbytesizeを使い分けよう
ここまで見てきたように、RubyのString#lengthは「文字数」、String#bytesizeは「データ容量(バイト数)」を表します。
- 文字数を数えたいとき →
length - データサイズを知りたいとき →
bytesize
特に日本語や絵文字などマルチバイト文字を扱うときには、UTF-8での1文字=複数バイトという点を忘れずに、目的に応じたメソッドを選びましょう。
まとめ
Rubyのlengthとbytesizeを正しく理解する重要性
この記事では、Rubyにおける String#length と String#bytesize の違いについて、UTF-8を中心とした文字コードの仕組みとあわせて詳しく解説してきました。Rubyで文字列を扱う際、「文字数」と「バイト数」を同じものとして考えてしまうと、思わぬ不具合や仕様ミスにつながることがあります。特に日本語を含むアプリケーション開発では、この違いを正しく理解しているかどうかが、プログラムの品質に大きく影響します。
length は、人が目で見て認識する「文字の数」を数えるためのメソッドです。ひらがな、カタカナ、漢字、英数字など、文字の種類に関係なく、表示される文字の個数をそのまま返します。そのため、入力フォームの文字数制限や、文章の長さチェック、投稿文字数の判定など、「ユーザーが意識する文字数」を扱う場面では length を使うのが自然です。
一方で bytesize は、文字列が内部的にどれくらいのデータ量を持っているか、つまり「バイト数」を返します。UTF-8では、日本語や多くの記号が1文字あたり複数バイトで表現されるため、見た目の文字数と実際のバイト数が一致しません。この特性は、ファイル保存時のサイズ計算や、ネットワーク通信、外部API連携など、データ量そのものが重要になる処理で特に重要です。
また、Rubyの文字列はエンコーディング情報を保持しており、UTF-8やShift_JISなど、文字コードが変わると bytesize の結果も変化します。同じ日本語の文字列でも、使用するエンコーディングによってバイト数が異なるため、環境依存の不具合を防ぐためにも、エンコーディングを意識した設計が欠かせません。
初心者がつまずきやすいポイントとして、「文字数を制限したいのに bytesize を使ってしまう」「ファイルサイズを知りたいのに length を使ってしまう」といったケースがあります。これらは一見小さな違いに見えますが、実際の開発現場では致命的なバグにつながることもあります。だからこそ、Rubyで文字列操作を行う際は、「今、自分は何を数えたいのか」を常に意識することが大切です。
まとめとしての確認用サンプルプログラム
def summary_check(str)
puts "対象の文字列: #{str}"
puts "文字数(length): #{str.length}"
puts "バイト数(bytesize): #{str.bytesize}"
puts "使用中のエンコーディング: #{str.encoding}"
puts "----------------------------"
end
summary_check("Ruby")
summary_check("日本語テキスト")
このサンプルでは、同じ仕組みで英語と日本語の文字列をチェックしています。出力結果を見ることで、文字数は同じ考え方で数えられている一方、バイト数は文字の種類やエンコーディングによって大きく変わることが直感的に理解できます。実際の開発でも、このように確認しながら進めることで、ミスを未然に防ぐことができます。
生徒
「length と bytesize が全然違う役割だということが、やっと腑に落ちました。今までは何となく使っていました。」
先生
「それに気付けたのは大きな成長ですね。Rubyでは文字列の扱いがとても柔軟なので、仕組みを理解すると応用が利くようになります。」
生徒
「文字数制限のときは length、データ量やサイズを見るときは bytesize、と使い分ければいいんですね。」
先生
「その通りです。さらにエンコーディングも意識できるようになると、文字化けや不具合にも強くなりますよ。」
生徒
「Rubyで日本語を扱うときに注意すべき理由が、よく分かりました。」
先生
「理解できていれば大丈夫です。ぜひ実際のプログラムでも、length と bytesize を意識して使ってみてください。」