各言語でUTF-8のバイト列を読み込み、バイト数とUnicodeでの文字数を取得してみたメモ。
要件は以下の通り。
- 標準入力から、文字列が1行だけ入力される。
- 標準出力に、以下の3つを改行区切りで出力する。
- 文字列の総バイト数
- 長さ
- 入力文字列そのもの
環境
手元にあるものということで、環境は以下のものに限定する。
- CentOS 7
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}"