日本語のバイト数についてお探しですね。
広告
日本語の文字数・バイト数の扱い方を徹底解説
Webアプリを作っていると、日本語の文字数やバイト数の扱いで悩むことってありますよね。
データベースに保存しようとしたら「文字数オーバーです」ってエラーが出たり、画面に表示している文字数カウントが実際の見た目と全然合わなかったり…。
こうした経験、一度はあるんじゃないでしょうか。
この記事では、文字コードによって変わる日本語のバイト数の計算方法や、UTF-8やUnicode(UTF-16)で正確に「1文字」を数える方法について、できるだけわかりやすく説明していきます。
文字コードによって変わる日本語のバイト数
文字列の長さを扱うとき、まず知っておきたいのが「文字コードによって1文字のバイト数が全然違う」ということです。
コンピュータは文字をそのまま理解できないので、文字を数字(バイト)の並びに変換して扱います。
この変換ルールが「文字コード」なんですが、歴史的な理由でいろんな種類があって、今よく使われているのがUTF-8やShift_JISといったものです。
日本語を表すとき、文字コードによって使うバイト数がかなり変わります。
たとえば昔よく使われていたShift_JISでは、半角英数字は1バイト、日本語の全角文字は2バイトでした。
文字数とバイト数の関係がわかりやすかったので、昔のシステムでは扱いやすかったんですね。
でも、今のWeb標準になっているUTF-8では、文字の種類によってバイト数が変わります。
**UTF-8でのバイト数の目安:**
– 半角英数字や記号(ASCII文字):1バイト
– ひらがな、カタカナ、よく使う漢字:3バイト
– 珍しい漢字や絵文字:4バイト
このように、UTF-8では基本的に「日本語1文字=3バイト」なんですが、例外もあるので単純に掛け算すればいいってわけじゃないんです。
データベースで「VARCHAR(255)」みたいに設定するとき、これが文字数の上限なのかバイト数の上限なのかは、使っているデータベースによって違います。
文字化けや文字切れを防ぐには、システム全体で文字コードの仕様をちゃんと理解しておくことが大切です。
UTF-8とUTF-16での「1文字」の数え方
文字数カウントをややこしくしているもう一つの理由が、プログラムの内部で使われる文字コード(主にUTF-16)と、外部とのやり取りで使う文字コード(UTF-8)が違うことです。
JavaScriptやJavaなどの言語は、メモリの中で文字列をUTF-16という形式で保持しています。
UTF-16では、よく使う文字のほとんどを「1コードユニット(2バイト)」で表現します。
ここまではシンプルなんですが、世界中のあらゆる文字や記号を収録するUnicodeが拡張されていくうちに、2バイトだけでは全部の文字を表現しきれなくなってしまいました。
そこで登場したのが「サロゲートペア」という仕組みです。
これは、めったに使わない漢字(例:「𠮷」の正式な字)や絵文字を表すために、2つのコードユニット(合計4バイト)を組み合わせて1文字を表す方法です。
このサロゲートペアのせいで、プログラムでの「1文字」の概念がややこしくなっています。
人間から見れば「𠮷」も「あ」も同じ1文字ですが、UTF-16ベースで動くプログラムは「あ」を1文字、「𠮷」を2文字として認識してしまうことがあるんです。
つまり、普通の関数で文字数を数えると、見た目と実際の数がズレちゃうわけです。
UTF-8でも同じような問題があります。
UTF-8は可変長なので、1文字が1バイトから4バイトまで変わります。
文字列の長さを単純にバイトの配列として数えると、日本語が入った瞬間に「文字数」じゃなくて「バイト数」が返ってきちゃいます。
だから、「人間にとっての1文字」を正確に数えるには、使っている言語や文字コードの特性に合わせた専用の方法が必要なんです。
【言語別】バイト数・文字数の取得方法
実際の開発では、プログラミング言語ごとの違いを理解して、適切な関数を使い分ける必要があります。
ここでは、Web開発でよく使うJavaScript、PHP、Javaの3つを例に説明しますね。
JavaScript
標準の「String.length」プロパティは、UTF-16のコードユニット数を返します。
だから、サロゲートペアを含む文字や絵文字を入れると、1文字なのに「2」とカウントされちゃいます。
これを解決するには、スプレッド構文を使って文字列を配列に展開する方法が有効です。
こうすることで、多くのサロゲートペア文字を正確にカウントできます。
“`javascript
const str = “あ𠮷い”;
console.log(str.length); // 4(コードユニット数)
console.log([…str].length); // 3(文字数)
“`
PHP
PHPは昔からいろんな文字コードを扱ってきたので、マルチバイト文字列用の関数が充実しています。
単に「strlen()」を使うと文字列のバイト数が返ってくるので、日本語を扱うときは「mb_strlen()」を使うのが基本です。
この関数を使うときは、内部エンコーディングが正しくUTF-8などに設定されているか確認してくださいね。
“`php
$str = “あいう”;
echo strlen($str); // 9(バイト数)
echo mb_strlen($str, ‘UTF-8’); // 3(文字数)
“`
Java
Javaで文字数を取得するときも、基本は「length()」メソッドを使います。
でも、データベースの制限に合わせて厳密なバイト数が必要な場合は、エンコーディングを指定してバイト配列に変換する必要があります。
“`java
String str = “あいう”;
int charCount = str.length(); // 3(文字数)
int byteCount = str.getBytes(“UTF-8”).length; // 9(バイト数)
“`
**まとめると:**
– **JavaScript**:文字数は「[…str].length」、標準のlengthはコードユニット数なので注意
– **PHP**:文字数は「mb_strlen()」、バイト数は「strlen()」を使い分ける
– **Java**:文字数は「length()」、UTF-8のバイト数は「getBytes(“UTF-8”).length」
どの言語でも、標準で用意されている関数が「何を数えているのか(バイト?コードユニット?文字?)」を公式ドキュメントで確認する癖をつけておくといいですよ。
絵文字や特殊文字を正しくカウントする方法
最近のWebアプリでは、絵文字や特殊文字への対応が避けられない課題になっています。
サロゲートペアだけでも大変なのに、さらにややこしいのが「絵文字シーケンス」という仕組みです。
これは、複数の独立した文字を特殊な制御文字でつなげて、見た目上1つの絵文字として表示する技術です。
たとえば「家族」を表す特定の絵文字は、男性、女性、少女、少年の4つの絵文字と、それらをくっつける制御文字(ゼロ幅接合子)から構成されています。
この文字列をJavaScriptのスプレッド構文で分割してカウントすると、結合要素も含めて7文字以上と判定されちゃいます。
ユーザーから見れば明らかに1文字なのに、システム上では長い文字列として扱われてしまうので、厳しい文字数制限を設けている入力フォームなどで予期せぬエラーの原因になります。
こうした見た目上の1文字(書記素クラスター)を正確にカウントするには、最新のAPIや専用のライブラリを使う必要があります。
JavaScriptなら、国際化APIの「Intl.Segmenter」を使うのが今のベストプラクティスです。
これを使えば、言語固有のルールや絵文字シーケンスの結合規則を解釈して、人間が見ている通りの単位で文字列を分割・カウントできます。
“`javascript
const segmenter = new Intl.Segmenter(‘ja’, { granularity: ‘grapheme’ });
const str = “👨👩👧👦あ”;
const segments = […segmenter.segment(str)];
console.log(segments.length); // 2(見た目通りの文字数)
“`
ただし、実行環境によっては最新のAPIが完全にサポートされていない場合もあるので、その場合は文字分割専用の外部ライブラリを導入するのも有効です。
プロジェクトの要件として「どこまで厳密な文字数カウントが必要か」をチームで話し合うことも大切です。
場合によっては「複雑な絵文字は複数文字としてカウントされても許容する」という割り切りが、システムを過度に複雑にしないための現実的な選択肢になることもあります。
文字数カウントは奥が深いですが、基本を押さえておけば多くのケースに対応できます。
ぜひこの記事を参考に、安心して日本語を扱えるシステムを作ってくださいね!
広告
