画面にこう出れば正解
どの言語で書いても、同じ入力なら画面に出る文字は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): 1510言語のプログラム
どれもそのまま保存して動かせます。毎朝、上の正解の例をすべて実際に動かして確かめています。
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
length.py3.14.7 で 6 / 6 件の出力が正解と一致
# 文字列の「文字数」と「バイト数(UTF-8)」を出す
import sys
s = sys.argv[1]
print(f"文字数: {len(s)}") # Python の len は、Unicode の文字(コードポイント)の数
print(f"バイト数(UTF-8): {len(s.encode('utf-8'))}") # バイト数は、UTF-8 のバイト列に直してから数える
動かし方(ファイルを保存したフォルダで) ・ Python を入れる
$ python3 length.py abc
length.go1.27.2 で 6 / 6 件の出力が正解と一致
// 文字列の「文字数」と「バイト数(UTF-8)」を出す
package main
import (
"fmt"
"os"
"unicode/utf8"
)
func main() {
s := os.Args[1]
// Go の len はバイト数を数える。文字(rune)の数は utf8.RuneCountInString で数える
fmt.Printf("文字数: %d\n", utf8.RuneCountInString(s))
fmt.Printf("バイト数(UTF-8): %d\n", len(s))
}
動かし方(ファイルを保存したフォルダで) ・ Go を入れる
$ go run length.go abc
length.js24.15.0 で 6 / 6 件の出力が正解と一致
// 文字列の「文字数」と「バイト数(UTF-8)」を出す
const s = process.argv[2];
// length は UTF-16 の単位を数える(「𠮷」は 2)。[...s] で1文字ずつに分けてから数える
console.log(`文字数: ${[...s].length}`);
console.log(`バイト数(UTF-8): ${Buffer.byteLength(s, "utf8")}`);
動かし方(ファイルを保存したフォルダで) ・ JavaScript を入れる
$ node length.js abc
Length.java21.0.12 で 6 / 6 件の出力が正解と一致
// 文字列の「文字数」と「バイト数(UTF-8)」を出す
import java.nio.charset.StandardCharsets;
public class Length {
public static void main(String[] args) {
String s = args[0];
// length() は UTF-16 の単位を数えるので「𠮷」や絵文字が 2 になる。codePointCount で Unicode の文字を数える
System.out.println("文字数: " + s.codePointCount(0, s.length()));
System.out.println("バイト数(UTF-8): " + s.getBytes(StandardCharsets.UTF_8).length);
}
}
動かし方(ファイルを保存したフォルダで) ・ Java を入れる
$ java Length.java abc
length.cs10.0.402 で 6 / 6 件の出力が正解と一致
// 文字列の「文字数」と「バイト数(UTF-8)」を出す
using System.Text;
string s = args[0];
// Length は UTF-16 の単位を数えるので「𠮷」や絵文字が 2 になる。EnumerateRunes で Unicode の文字を数える
Console.WriteLine($"文字数: {s.EnumerateRunes().Count()}");
Console.WriteLine($"バイト数(UTF-8): {Encoding.UTF8.GetByteCount(s)}");
動かし方(ファイルを保存したフォルダで) ・ C# を入れる
$ dotnet run length.cs -- abc
length.rs1.99.0 で 6 / 6 件の出力が正解と一致
// 文字列の「文字数」と「バイト数(UTF-8)」を出す
fn main() {
let args: Vec<String> = std::env::args().collect();
let s = &args[1];
// len() は UTF-8 のバイト数を返す。Unicode の文字の数は chars().count() で数える
println!("文字数: {}", s.chars().count());
println!("バイト数(UTF-8): {}", s.len());
}
動かし方(ファイルを保存したフォルダで) ・ Rust を入れる
$ rustc length.rs && ./length abc
length.rb4.0.7 で 6 / 6 件の出力が正解と一致
# 文字列の「文字数」と「バイト数(UTF-8)」を出す
s = ARGV[0]
puts "文字数: #{s.length}" # Ruby の length は、Unicode の文字(コードポイント)の数
puts "バイト数(UTF-8): #{s.bytesize}" # bytesize はバイト数
動かし方(ファイルを保存したフォルダで) ・ Ruby を入れる
$ ruby length.rb abc
length.kt2.4.21 で 6 / 6 件の出力が正解と一致
// 文字列の「文字数」と「バイト数(UTF-8)」を出す
fun main(args: Array<String>) {
val s = args[0]
// length は UTF-16 の単位を数えるので「𠮷」や絵文字が 2 になる。codePointCount で Unicode の文字を数える
println("文字数: ${s.codePointCount(0, s.length)}")
println("バイト数(UTF-8): ${s.toByteArray(Charsets.UTF_8).size}")
}
動かし方(ファイルを保存したフォルダで) ・ Kotlin を入れる
$ kotlinc length.kt -include-runtime -d length.jar && java -jar length.jar abc
length.swift6.3.3 で 6 / 6 件の出力が正解と一致
// 文字列の「文字数」と「バイト数(UTF-8)」を出す
let s = CommandLine.arguments[1]
// count は見た目の1文字(家族の絵文字は 1)を数える。unicodeScalars.count で Unicode の文字を数える
print("文字数: \(s.unicodeScalars.count)")
print("バイト数(UTF-8): \(s.utf8.count)")
動かし方(ファイルを保存したフォルダで) ・ Swift を入れる
$ swift length.swift abc
言語でつまずきやすいところ
初心者がよく書く形(各言語で最初に習う書き方をそのまま使ったもの)を、同じ正解表で動かした結果です。言語を出した答えごとにまとめ、赤い字はその言語が実際に出した間違った行です。
| 入力 | 初心者がよく書く形の答え(10言語) |
|---|---|
英字abc | ✓10言語すべて正解 |
ひらがなあいう |
|
めずらしい漢字(𠮷)𠮷野家 |
|
絵文字👍 |
|
組み合わせた絵文字(家族)家族👨👩👧 |
|
全角と半角が混ざるカナカナ123 |
|
この回でやること
- 文字列の長さを調べる関数を使う
- 「文字数」と「バイト数」の違いを知る
解説
文字数は、数え方が3つある
コンピュータの中で、文字は番号(文字コード)で表されます。どの単位で数えるかで、答えが変わります。
| 数え方 | 「あ」 | 「𠮷」 | 「👍」 | この数え方をする関数の例 |
|---|---|---|---|---|
| Unicode の文字(コードポイント) | 1 | 1 | 1 | Python の len、Ruby の length、Rust の chars().count()、Go の utf8.RuneCountInString |
| UTF-16 の単位 | 1 | 2 | 2 | JavaScript の length、Java・Kotlin の length()、C# の Length |
| UTF-8 のバイト | 3 | 4 | 4 | Go・Rust の len、PHP の strlen |
| 見た目の1文字(書記素) | 1 | 1 | 1 | Swift の 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文字で出るでしょうか
- 文字列を逆順にして出してみましょう