各言語でUTF-8バイト列を文字列置換および文字列分割してみる
各言語でUTF-8のバイト列を読み込み、文字列置換と文字列分割をしてみたメモ。
要件は以下の通り。
- 標準入力から、文字列が1行だけ入力される。
- 標準出力に、以下の2つを改行区切りで出力する。
- 文字列の各文字をすべて'.'で置き換えた文字列
- 入力文字列の各文字を改行で区切ったもの
- つまり、10文字の文字列が入力されたら、出力は11行になる
環境
手元にあるものということで、環境は以下のものに限定する。
- 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.replaceAll(".", ".")); // 文字列分割 for (int i = 0; i < s.length(); ++i) { char ch1 = s.charAt(i); out.print(ch1); if (Character.isSurrogate(ch1)) { ++i; char ch2 = s.charAt(i); out.print(ch2); } out.println(); } } catch (IOException e) { e.printStackTrace(); } } }
C
#include <stdio.h> #include <string.h> #include <locale.h> #include <stdlib.h> #include <regex.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'; } regex_t rb; if (regcomp(&rb, ".", REG_EXTENDED | REG_NEWLINE)) { perror("regcomp"); return 1; } const char* p; regmatch_t rm; int err; int idx; // 文字列置換 p = str; idx = 0; do { err = regexec(&rb, p + idx, 1, &rm, 0); if (!err) { if (rm.rm_so > 0) { char buf[1024]; memset(buf, '\0', sizeof(buf)); strncpy(buf, p + idx, rm.rm_so); fprintf(stdout, "%s", buf); } fprintf(stdout, "."); idx += rm.rm_eo; } } while (!err); fprintf(stdout, "%s\n", p + idx); // 文字列分割 p = str; idx = 0; do { err = regexec(&rb, p + idx, 1, &rm, 0); if (!err) { char buf[1024]; memset(buf, '\0', sizeof(buf)); strncpy(buf, p + idx + rm.rm_so, rm.rm_eo - rm.rm_so); fprintf(stdout, "%s\n", buf); idx += rm.rm_eo; } } while (!err); regfree(&rb); return 0; }
C++
#include <iostream> #include <locale> #include <string> using namespace std; int main(int argc, char** argv) { setlocale(LC_ALL, "ja_JP.UTF-8"); wcout.imbue(locale("japanese")); wstring str; getline(wcin, str); // 文字列置換(ごまかし) // regex_matchが完全マッチにしか対応してなくて使えないので。 for (int i = 0; i < str.length(); ++i) { wcout << L"."; } wcout << endl; // 文字列分割(ごまかし) // regex_matchが完全マッチにしか対応してなくて使えないので。 for (int i = 0; i < str.length(); ++i) { wcout << str[i] << endl; } return EXIT_SUCCESS; }
(2017/12/05追記)
「yum install boost-devel」してBoostのライブラリを使うようにしたらまともに動いてくれたので、そのソースコードを追記。コンパイル時に「-lboost_regex」が必要。
#include <iostream> #include <locale> #include <string> #include <boost/regex.hpp> using namespace std; int main(int argc, char** argv) { setlocale(LC_ALL, "ja_JP.UTF-8"); wcout.imbue(locale("japanese")); wstring str; getline(wcin, str); boost::wregex re(L"."); // 文字列置換 wcout << boost::regex_replace(str, re, L".") << endl; // 文字列分割 boost::wsmatch sm; wstring::const_iterator start = str.begin(); wstring::const_iterator end = str.end(); int offset = 0; while (boost::regex_search(start + offset, end, sm, re)) { size_t idx = 0; for (int i = 0; i < sm.length(idx); ++i) { wcout << str[sm.position(idx) + offset + i]; } wcout << endl; offset += sm.position(idx) + sm.length(idx); } return EXIT_SUCCESS; }
PHP
<?php $str = file_get_contents('php://stdin'); $str = trim($str); mb_regex_encoding('UTF-8'); // 文字列置換 // mb_xxx系ではereg版しかない // パターンの書き方がpreg系の関数と違うことに注意・・ echo mb_ereg_replace('.', '.', $str) . PHP_EOL; // 文字列分割 // mb_xxx系ではereg版しかない // パターンの書き方がpreg系の関数と違うことに注意・・ $tmp = $str; do { mb_ereg_search_init($tmp, '.'); $range = mb_ereg_search_pos(); if ($range !== false) { echo substr($tmp, $range[0], $range[1]) . PHP_EOL; $tmp = substr($tmp, $range[1]); } } while ($tmp !== false && $range !== false);
Python 2
# -*- coding: UTF-8 -*- import sys import re s = sys.stdin.readline() ustr = unicode(s, 'UTF-8') ustr = ustr.replace('\n', '') ustr = ustr.replace('\r', '') # 文字列置換 print re.sub(r'.', '.', ustr) # 文字列分割 for i in range(0, len(ustr)): print ustr[i].encode('UTF-8')
Python 3
# -*- coding: UTF-8 -*- import sys import re b = sys.stdin.buffer.readline() s = str(b, 'UTF-8') s = s.replace('\n', '') s = s.replace('\r', '') # 文字列置換 print(re.sub(r'.', '.', s)) # 文字列分割 for i in range(0, len(s)): print(s[i])
Ruby
str = STDIN.gets str.chomp!() # 文字列置換 print str.gsub(/./, '.'),"\n" # 文字列分割 for i in 0...str.size() print str[i],"\n" end
Perl
use Encode; my $str = readline(STDIN); chomp($str); # 文字列置換 my $ustr = decode('UTF-8', $str); my $tmp = $ustr; $tmp =~ s/././g; print $tmp,"\n"; # 文字列分割 my $tmp = $ustr; for (my $i = 0; $i < length($ustr); ++$i) { print encode('UTF-8', substr($tmp, $i, 1)),"\n"; }
Go
package main import ( "fmt" "os" "io" "bufio" "regexp" ) 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) ss := regexp.MustCompile(`.`).ReplaceAllString(s, ".") fmt.Println(ss) runes := []rune(s) for i := 0; i < len(runes); i += 1 { fmt.Println(string(runes[i])) } }
bash
#! /bin/bash IFS= read s echo "${s}" | sed -e 's/././g' echo -n "${s}" | sed -e 's/\(.\)/\1\n/g'