HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

各言語でUTF-8バイト列からバイト数と文字数を取ってみる

各言語でUTF-8のバイト列を読み込み、バイト数とUnicodeでの文字数を取得してみたメモ。

要件は以下の通り。

  • 標準入力から、文字列が1行だけ入力される。
  • 標準出力に、以下の3つを改行区切りで出力する。
    • 文字列の総バイト数
    • 長さ
    • 入力文字列そのもの

環境

手元にあるものということで、環境は以下のものに限定する。

Java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;

public class Main {
    public static void main(String[] args) {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            PrintWriter out = new PrintWriter(System.out)
        ) {
            String s = in.readLine();
            out.println(s.getBytes().length);
            out.println(s.codePointCount(0, s.length()));
            out.println(s);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Javaは、歴史的経緯から、サロゲートペアをcharで表すことができないので、文字数を知りたいときにString.length()を呼んではダメ。

C

#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <wchar.h>
#include <stdlib.h>

int main(int argc, char** argv) {
    setlocale(LC_ALL, "ja_JP.UTF-8");

    char str[1024];

    fgets(str, sizeof(str), stdin);
    while (str[strlen(str) - 1] == '\n' || str[strlen(str) - 1] == '\r') {
        str[strlen(str) - 1] = '\0';
    }

    fprintf(stdout, "%d\n", strlen(str));

    wchar_t buf[1024];
    const char* p = str;
    mbsrtowcs(buf, &p, sizeof(buf), NULL);
    fprintf(stdout, "%d\n", wcslen(buf));

    fprintf(stdout, "%s\n", str);

    return 0;
}

C++

#include <iostream>
#include <cwchar>
#include <clocale>
#include <string>
#include <cstring>

using namespace std;

int main(int argc, char** argv) {
    setlocale(LC_ALL, "ja_JP.UTF-8");

    wstring str;
    getline(wcin, str);

    char cbuf[1024];
    wcstombs(cbuf, str.c_str(), sizeof(cbuf));
    wcout << strlen(cbuf) << endl;

    wcout << str.length() << endl;

    wcout << str << endl;

    return EXIT_SUCCESS;
}

PHP

<?php

$str = file_get_contents('php://stdin');
$str = trim($str);

echo strlen($str) . PHP_EOL;

echo mb_strlen($str, 'UTF-8') . PHP_EOL;

echo $str . PHP_EOL;

Python 2

import sys

s = sys.stdin.readline()
s = s.replace('\n', '')
s = s.replace('\r', '')

print len(s)

ustr = unicode(s, 'UTF-8')
print len(ustr)

print s

Python 3

import sys

b = sys.stdin.buffer.readline()
s = str(b, 'UTF-8')
s = s.replace('\n', '')
s = s.replace('\r', '')
b = bytes(s, 'UTF-8')

print(len(b))

print(len(s))

print(s)

Ruby

str = STDIN.gets
str.chomp!()

print str.bytes().size(),"\n"

print str.size(),"\n"

print str,"\n"

Perl

use Encode;

my $str = readline(STDIN);
chomp($str);

print length($str),"\n";

my $b = $str;
$b = decode('UTF-8', $b);
print length($b),"\n";

print $str,"\n";

Go

package main

import (
    "fmt"
    "os"
    "io"
    "bufio"
)

func ReadLine(reader *bufio.Reader) (s string, err error) {
    prefix := false
    buf := make([]byte, 0)
    var line []byte
    for {
        line, prefix, err = reader.ReadLine()
        if err == io.EOF {
            return
        }
        buf = append(buf, line...)
        if prefix {
            continue
        }
        s = string(buf)
        return
    }
}

func main() {
    stdin := bufio.NewReader(os.Stdin)
    s, _ := ReadLine(stdin)

    fmt.Println(len(s))

    runes := []rune(s)
    fmt.Println(len(runes))

    fmt.Println(s)
}

bash

#! /bin/bash

IFS= read s

echo -n "${s}" | wc -c

echo ${#s}

echo "${s}"

まさか、サロゲートペアを含む文字列の文字数をシェルスクリプトでちゃんと取れるとは思ってなかった。