CODE Polyglot / 入門 / 第4回

文字数を数える — 同じ文字列でも、数え方で答えが変わる

受け取った文字列の「文字数」と「バイト数(UTF-8)」を出します。「𠮷」や絵文字を、2文字と数える言語・1文字と数える言語・4と数える言語があります。

画面にこう出れば正解

どの言語で書いても、同じ入力なら画面に出る文字は1文字も違わない、というのが正解の決め方です(例は Python で動かしたときのコマンドです)。

英字

$ python3 length.py abc
文字数: 3
バイト数(UTF-8): 3

ひらがな

$ python3 length.py あいう
文字数: 3
バイト数(UTF-8): 9

めずらしい漢字(𠮷)

$ python3 length.py 𠮷野家
文字数: 3
バイト数(UTF-8): 10

絵文字

$ python3 length.py 👍
文字数: 1
バイト数(UTF-8): 4

組み合わせた絵文字(家族)

$ python3 length.py 家族👨‍👩‍👧
文字数: 7
バイト数(UTF-8): 24

全角と半角が混ざる

$ python3 length.py カナカナ123
文字数: 7
バイト数(UTF-8): 15

10言語のプログラム

どれもそのまま保存して動かせます。毎朝、上の正解の例をすべて実際に動かして確かめています。

length.php8.4.26 で 6 / 6 件の出力が正解と一致

<?php
// 文字列の「文字数」と「バイト数(UTF-8)」を出す
$s = $argv[1];
// strlen はバイト数を数える。文字数は、u(UTF-8)を付けた正規表現で「1文字」を数える
$chars = preg_match_all('/./su', $s);
echo "文字数: " . $chars . "\n";
echo "バイト数(UTF-8): " . strlen($s) . "\n";

動かし方(ファイルを保存したフォルダで) ・ PHP を入れる

$ php length.php abc

言語でつまずきやすいところ

初心者がよく書く形(各言語で最初に習う書き方をそのまま使ったもの)を、同じ正解表で動かした結果です。言語を出した答えごとにまとめ、赤い字はその言語が実際に出した間違った行です。

入力初心者がよく書く形の答え(10言語)
英字abc

✓10言語すべて正解

ひらがなあいう
  • PHP・Go・Rust文字数: 9
  • Python・JavaScript・Java・C#・Ruby・Kotlin・Swift✓ 正解
めずらしい漢字(𠮷)𠮷野家
  • PHP・Go・Rust文字数: 10
  • JavaScript・Java・C#・Kotlin文字数: 4
  • Python・Ruby・Swift✓ 正解
絵文字👍
  • PHP・Go・Rust文字数: 4
  • JavaScript・Java・C#・Kotlin文字数: 2
  • Python・Ruby・Swift✓ 正解
組み合わせた絵文字(家族)家族👨‍👩‍👧
  • PHP・Go・Rust文字数: 24
  • JavaScript・Java・C#・Kotlin文字数: 10
  • Swift文字数: 3
  • Python・Ruby✓ 正解
全角と半角が混ざるカナカナ123
  • PHP・Go・Rust文字数: 15
  • Python・JavaScript・Java・C#・Ruby・Kotlin・Swift✓ 正解

この回でやること

  • 文字列の長さを調べる関数を使う
  • 「文字数」と「バイト数」の違いを知る

解説

文字数は、数え方が3つある

コンピュータの中で、文字は番号(文字コード)で表されます。どの単位で数えるかで、答えが変わります。

数え方「あ」「𠮷」「👍」この数え方をする関数の例
Unicode の文字(コードポイント)111Python の len、Ruby の length、Rust の chars().count()、Go の utf8.RuneCountInString
UTF-16 の単位122JavaScript の length、Java・Kotlin の length()、C# の Length
UTF-8 のバイト344Go・Rust の len、PHP の strlen
見た目の1文字(書記素)111Swift の count

この回では、1つめの「Unicode の文字」の数を「文字数」、3つめを「バイト数」と決めて出しています。PHP では mb_strlen が1つめの数え方ですが、mbstring という拡張が入っていないと使えないので、この回の PHP のプログラムは正規表現で数えています。

「𠮷」(つちよし)や絵文字は、UTF-16 では2つの単位を組み合わせて表します。そのため JavaScript や Java の length は 2 と数えます。

見た目の1文字が、いくつもの文字でできていることもある

家族の絵文字「👨‍👩‍👧」は、見た目は1文字ですが、中身は「男性・つなぎ記号・女性・つなぎ記号・女の子」の5つの文字です。Swift の count は見た目の1文字(書記素)で数えるので 1、ほかの言語のコードポイントの数え方では 5 になります。

つまずきやすいところ

  • 入力欄の「最大10文字」を JavaScript の length で調べると、絵文字の入った名前が早めに「長すぎる」になります
  • データベースの列の長さが「バイト数」で決まっていると、日本語は1文字で3バイト使います

練習

  1. 文字列を1文字ずつ改行して出してみましょう。「𠮷」が正しく1文字で出るでしょうか
  2. 文字列を逆順にして出してみましょう